package demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.Callable;
#SpringBootApplication
#Slf4j
#EnableAsync
public class DemoApplication {
#RestController
public static class MyController {
#GetMapping("/callable")
public Callable<String> callable() throws InterruptedException {
log.info("callable");
return ()-> {
log.info("async");
Thread.sleep(2000);
return "hello";
};
}
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
The code above is the spring project code.
I predicted that when http:localhost:8080/callable is called, "Hello" will be output in 2 seconds, but {} will be output.
In my console printed "Callable" but not printed "Async" Plz help me why my code not work??
i add my pom.xml file
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
WebFlux expects a Publisher(Mono/Flux) to be returned by the Controller. You can create a Mono by providing a Callable like this:
#GetMapping("/callable")
public Mono<String> callable() throws InterruptedException {
log.info("callable");
return Mono.fromCallable(() -> {
log.info("async");
Thread.sleep(2000);
return "hello";
});
}
As a side note, Thread.sleep should never be used within a reactive pipeline in actual application code.
Related
I have a test project where I'm trying to setup e2e api tests using rest-assured. Tests run fine if I run them from the feature files, however, when I try to run them with maven, 0 tests run. I believe there is something funky with my pom.xml but I can't figure it out...
My project structure looks like:this
My pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.0</version>
</parent>
<artifactId>qa-automation-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<groupId>com</groupId>
<packaging>jar</packaging>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-bom</artifactId>
<version>7.2.3</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-path</artifactId>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>xml-path</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<properties>
<configurationParameters>
cucumber.junit-platform.naming-strategy=long
</configurationParameters>
</properties>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
My Application.java
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
#PropertySources({
#PropertySource("classpath:application.properties")
})
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
My CucumberSpringConfiguration.class
import io.cucumber.spring.CucumberContextConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import com.Application;
#CucumberContextConfiguration
#SpringBootTest(classes = Application.class)
public class CucumberSpringConfiguration {
}
My CucumberTest.java
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
#Suite
#IncludeEngines("cucumber")
#SelectClasspathResource("src/test/resources/example")
#ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example")
public class CucumberTest {
}
I'm not really familiar with Spring though so I'm pretty sure I'm not using it correctly in my ApiTestStepDef.java
package com.example;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import io.cucumber.java.en.Given;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.Assertions;
import org.springframework.beans.factory.annotation.Autowired;
import com.client.RestAssuredClient;
import com.model.User;
import com.utils.Helper;
import static io.restassured.RestAssured.given;
public class ApiTestStepDef {
private Response response;
private RequestSpecification request;
private User user;
private User responseBody;
#Autowired
private RestAssuredClient restAssuredClient;
#Given("{string} endpoint")
public void setBaseUsersURI(String url){
request =
given().log().all().
spec(restAssuredClient.createReqSpec(url));
}
#When("user posts request with details {string} {string} {string}")
public void sendRequest(String name, String gender, String status){
user = new User(name, gender, Helper.createRandomEmail(), status);
response =
request.given().log().all().
body(user).
when().
post().
then().log().all().
extract().response();
}
#Then("response status code is {int} and response contains correct user details")
public void checkResponseStatusCode(int statusCode){
response.then().spec(restAssuredClient.createResSpec(statusCode));
responseBody = response.getBody().as(User.class);
Assertions.assertEquals(user.getGender(), responseBody.getGender());
Assertions.assertEquals(user.getStatus(), responseBody.getStatus());
Assertions.assertEquals(user.getEmail(), responseBody.getEmail());
Assertions.assertEquals(user.getName(), responseBody.getName());
}
}
And RestAssuredClient.java
package com.client;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import static io.restassured.RestAssured.oauth2;
#Component
public class RestAssuredClient {
#Value("${access.token}")
private String accessToken;
#Value("${base.uri}")
private String baseUri;
public ResponseSpecification createResSpec(int statusCode){
return
new ResponseSpecBuilder()
.expectStatusCode(statusCode)
.expectContentType(ContentType.JSON)
.build();
}
public RequestSpecification createReqSpec(String url){
return new RequestSpecBuilder()
.setBaseUri(baseUri)
.setContentType(ContentType.JSON)
.setAuth(oauth2(accessToken))
.setBasePath(url)
.build();
}
}
#SelectClasspathResource("src/test/resources/example")
Typically src/test/resources is not part of the classpath.
After running mvn test have a look at target/test-classes to understand the structure of what is on the classpath.
I'm running into an issue where I can't run JUnit5 tests using Maven. Running them in the IDE works just fine but using "mvn test" produces the following output:
T E S T S
[INFO] -------------------------------------------------------
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 0, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Here are my test classes :
package com.example.spstream.controllers.events;
import com.example.spstream.entities.Event;
import com.example.spstream.repositories.EventRepository;
import com.example.spstream.repositories.UserRepository;
import com.example.spstream.util.Mapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.dao.DataAccessException;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.time.LocalDateTime;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
#EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)
public class EventsCreationTest {
private static final String MISSING_TITLE_ERROR_MESSAGE = "title is missing";
private static final String MISSING_ACTIVITY_ERROR_MESSAGE = "activity is missing";
private static final String MISSING_LOCALISATION_ERROR_MESSAGE = "localisation is missing";
private static final String INVALID_ORGANISER_ID_ERROR_MESSAGE = "user %s does not exist";
private static final String MISSING_ORGANISER_ID_ERROR_MESSAGE = "organiser id is missing";
#Autowired
private MockMvc mockMvc;
#MockBean
private UserRepository userRepository;
#SpyBean
private EventRepository eventRepository;
private static final String DATE_IN_PAST_ERROR_MESSAGE = "date is in the past";
#BeforeEach
public void reset(){
Mockito.reset(userRepository);
Mockito.when(userRepository.existsById("123456")).thenReturn(true);
}
//prevents hardcoded events from failing tests due to date in the past
public void setEventDateToTomorrow(Event event) {
event.setDateTime(LocalDateTime.now().plusDays(1));
}
public void setEventDateToYesterday(Event event) {
event.setDateTime(LocalDateTime.now().minusDays(1));
}
public void testCorrectEventCreationWithEvent(Event event) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/events")
.content(Mapper.writeObjectToJson(event))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").exists())
.andExpect(jsonPath("$.id").isString());
}
public void testIncorrectEventCreationWithEvent(Event event, String errorMessagePattern) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/events")
.content(Mapper.writeObjectToJson(event))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andExpect(content().string(containsString(String.format(errorMessagePattern, event.getOrganiserId()))));
}
/**
* correct data
**/
#Test
public void testMinimalCorrectEvent() throws Exception {
Event minimalEvent = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
setEventDateToTomorrow(minimalEvent);
testCorrectEventCreationWithEvent(minimalEvent);
}
#Test
public void testMaximalCorrectEvent() throws Exception {
Event maximalEvent = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/maximal_event.json"), Event.class);
setEventDateToTomorrow(maximalEvent);
testCorrectEventCreationWithEvent(maximalEvent);
}
/**
* missing data
**/
#Test
public void testIncorrectEventTitleMissing() throws Exception {
Event eventTitleMissing = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
setEventDateToTomorrow(eventTitleMissing);
eventTitleMissing.setTitle(null);
testIncorrectEventCreationWithEvent(eventTitleMissing, MISSING_TITLE_ERROR_MESSAGE);
}
#Test
public void testIncorrectEventActivityMissing() throws Exception {
Event eventActivityMissing = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
eventActivityMissing.setActivity(null);
setEventDateToTomorrow(eventActivityMissing);
testIncorrectEventCreationWithEvent(eventActivityMissing, MISSING_ACTIVITY_ERROR_MESSAGE);
}
#Test
public void testIncorrectEventLocalisationMissing() throws Exception {
Event eventLocalisationMissing = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
eventLocalisationMissing.setLocalisation(null);
setEventDateToTomorrow(eventLocalisationMissing);
testIncorrectEventCreationWithEvent(eventLocalisationMissing, MISSING_LOCALISATION_ERROR_MESSAGE);
}
#Test
public void testIncorrectEventMissingUserId() throws Exception {
Event eventOrganiserIdMissing = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/incorrect/missing_user_id.json"), Event.class);
setEventDateToTomorrow(eventOrganiserIdMissing);
testIncorrectEventCreationWithEvent(eventOrganiserIdMissing, MISSING_ORGANISER_ID_ERROR_MESSAGE);
}
/**
* invalid data
**/
#Test
public void testIncorrectEventInvalidOrganiserId() throws Exception {
Mockito.when(userRepository.existsById(Mockito.any())).thenReturn(false);
Event eventInvalidOrganiserId = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
setEventDateToTomorrow(eventInvalidOrganiserId);
testIncorrectEventCreationWithEvent(eventInvalidOrganiserId, INVALID_ORGANISER_ID_ERROR_MESSAGE);
}
#Test
public void testIncorrectEventDateInThePast() throws Exception {
Event eventInPast = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
setEventDateToYesterday(eventInPast);
testIncorrectEventCreationWithEvent(eventInPast, DATE_IN_PAST_ERROR_MESSAGE);
}
/**
* internal database issue
**/
#Test
public void testCorrectEventServerError() throws Exception {
Event eventInvalidOrganiserId = Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/create/correct/minimal_event.json"), Event.class);
setEventDateToTomorrow(eventInvalidOrganiserId);
Mockito.when(eventRepository.save(eventInvalidOrganiserId)).thenThrow(Mockito.mock(DataAccessException.class));
mockMvc.perform(MockMvcRequestBuilders.post("/events")
.content(Mapper.writeObjectToJson(eventInvalidOrganiserId))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is5xxServerError());
System.out.println("whatever");
}
}
package com.example.spstream.controllers.events;
import com.example.spstream.entities.Event;
import com.example.spstream.repositories.EventRepository;
import com.example.spstream.util.Mapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.dao.DataAccessException;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.util.List;
import java.util.Optional;
import static com.example.spstream.util.Mapper.readJsonFromFile;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
#EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)
public class EventsAccessTest {
#MockBean
EventRepository mockEventRepository;
#Autowired
MockMvc mockMvc;
#BeforeEach
public void reset(){
Mockito.reset(mockEventRepository);
}
#Test
public void testFindAll() throws Exception{
List<Event> events = Mapper.readObjectListFromJson(readJsonFromFile("controllers/events/access/all_events.json"), Event.class);
Mockito.when(mockEventRepository.findAll()).thenReturn(events);
mockMvc.perform(MockMvcRequestBuilders.get("/events")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().json(Mapper.readJsonFromFile("controllers/events/access/all_events.json")));
}
#Test
public void testFindEventWhichExists() throws Exception{
Mockito.when(mockEventRepository.findById("123456")).thenReturn(Optional.of(Mapper.readObjectFromJson(Mapper.readJsonFromFile("controllers/events/access/final_event.json"),Event.class)));
mockMvc.perform(MockMvcRequestBuilders.get("/events/123456")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().json(Mapper.readJsonFromFile("controllers/events/access/final_event.json")));
}
#Test
public void testFindEventWhichDoesntExist() throws Exception {
Mockito.when(mockEventRepository.findById("7891011")).thenReturn(Optional.empty());
mockMvc.perform(MockMvcRequestBuilders.get("/events/7891011")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
#Test
public void testFindEventDatabaseError() throws Exception {
Mockito.when(mockEventRepository.findById("123456")).thenThrow(Mockito.mock(DataAccessException.class));
mockMvc.perform(MockMvcRequestBuilders.get("/events/123456")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is5xxServerError());
}
}
The pom :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spstream</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spstream</name>
<description>spstream</description>
<properties>
<java.version>17</java.version>
<testcontainers.version>1.16.2</testcontainers.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.32.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>3.0.0-M5</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
I have done some research and I figured it might have something to do mith mixing up JUnit4 and JUnit5 features which leads to maven surefire plugin not running tests. However I can't find where those leftover JUnit4 features might be.
I'd appreciate any help.
As pointed out by other comments and answers I had residual JUnit4 dependencies due to test containers. I was able to fix the issue by explicitly setting JUnit5 as a dependency for maven surefire plugin like so :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
</dependency>
</dependencies>
</plugin>
The Junit4 is available because of Testcontainer dependency.
Testcontainers have a dependency on Junit4 and have it available by default.
You might also encounter the following issue in few cases:
IDE's detects the test cases written in Junit4 format but in sometime in case you make the test classes and methods package-private, they don't detect it.
I am not sure if they would be removing it in further releases but they do have Junit5 support which should resolve the issue
https://www.testcontainers.org/test_framework_integration/junit_5/
I'm totally new to Resteasy and still learning how it works.
But I cannot work this code out.
I start the tomcat server and it should return fake users information, but somehow gets 404. (No error shown to Eclipse.) I already googled to figure out why this code doesn't work but I couldn't.
To get all users, the URI should be http://localhost:8080/api/v1/users
package com.demo.sprintSample.config;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import org.springframework.context.annotation.Configuration;
#Configuration
#ApplicationPath("/")
public class ResteasyConfig extends Application {
}
package com.demo.sprintSample.resource;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import com.demo.sprintSample.model.User;
import com.demo.sprintSample.service.UserService;
#Component
#Path("/api/v1/users")
public class UserResourceResteasy {
private UserService userService;
#Autowired
public UserResourceResteasy(UserService userService) {
this.userService = userService;
}
#GET
#Produces("application/json")
public List<User> getAllUsers() {
return userService.getAllUsers();
}
#GET
#Path("{userUid}")
#Produces("application/json")
public Response fetchUser(#PathParam("userUid") UUID userUid) {
Optional<User> userOptional = userService.getUser(userUid);
if(userOptional.isPresent()) {
return Response.ok(userOptional.get()).build();
}
return Response.status(Response.Status.NOT_FOUND)
.entity(new ErrorMessage("user"+userUid+"was not found."))
.build();
}
#POST
#Consumes("application/json")
#Produces("application/json")
public Response insertNewUser(#RequestBody User user) {
UUID uid = UUID.randomUUID();
int result = userService.insertUser(user);
return getIntegerResponseEntity(result);
}
#PUT
#Consumes("application/json")
#Produces("application/json")
public Response updateUser(#RequestBody User user) {
int result = userService.updateUser(user);
return getIntegerResponseEntity(result);
}
#DELETE
#Path("{userUid}")
public Response deleteUser(#PathParam("userUid") UUID userUid) {
int result =userService.removeUser(userUid);
return getIntegerResponseEntity(result);
}
private Response getIntegerResponseEntity(int result) {
if(result == 1) {
return Response.ok().build();
}
return Response.status(Response.Status.BAD_REQUEST).build();
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>sprintSample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sprintSample</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<rest.easy.client.version>4.5.6.Final</rest.easy.client.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.21.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>3.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>jaxrs-api</artifactId>
<version>3.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>3.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
I'm trying to run spring boot with spring data as basically as possible with swing.
However, even though all seems to be properly configured, when I try to run it, I get an error message saying it couldn't find my Service bean.
package db.westworld.dao;
import db.westworld.entities.RobotEntity;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface RobotRepository extends CrudRepository<RobotEntity, Integer> {
}
package db.westworld.service;
import db.westworld.entities.RobotEntity;
import java.util.Optional;
public interface IRobotService {
Optional<RobotEntity> findById(int id);
}
package db.westworld.service;
import db.westworld.dao.RobotRepository;
import db.westworld.entities.RobotEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
#Service
public class RobotService implements IRobotService {
private final RobotRepository robotRepository;
#Autowired
RobotService(RobotRepository robotRepository) {
this.robotRepository = robotRepository;
}
#Override
public Optional<RobotEntity> findById(int id) {
return robotRepository.findById(id);
}
public void saveRobot(RobotEntity robot) {
robotRepository.save(robot);
}
}
package db.westworld;
import db.westworld.view.RegisterRobot;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.awt.*;
#SpringBootApplication
public class WestworldApplication {
public static void main(String[] args) {
var ctx = new SpringApplicationBuilder(RegisterRobot.class).headless(false).run(args);
EventQueue.invokeLater(() -> {
var ex = ctx.getBean(RegisterRobot.class);
ex.setVisible(true);
});
}
}
package db.westworld.view;
import db.westworld.entities.RobotEntity;
import db.westworld.service.RobotService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import javax.swing.*;
import java.awt.event.*;
import java.util.Date;
#Controller
public class RegisterRobot extends JDialog {
private RobotService robotService;
#Autowired
public void setRobotService (RobotService robotService) {
this.robotService = robotService;
}
private void onOK() {
RobotEntity robot = new RobotEntity();
robot.setCreatedAt(new Date());
robot.setId(1);
robotService.saveRobot(robot);
dispose();
}
}
Error message:
Parameter 0 of method setRobotService in db.westworld.view.RegisterRobot required a bean of type 'db.westworld.service.RobotService' that could not be found.
Action:
Consider defining a bean of type 'db.westworld.service.RobotService' in your configuration.
(the JDialog implementation just includes the basics)
The same also happens when I try to autowire the repository.
Also, in case needed, here's my pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <groupId>db</groupId>
<artifactId>westworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>westworld</name>
<description>westworldSpringBoot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The parameter to new SpringApplicationBuilder() must be the class annotate with #SpringBootApplication, as shown in every Spring Boot example I've ever seen, e.g. Create an Application class in the "Getting Started - Building an Application with Spring Boot" guide.
It is a spring boot 2.0.0 application which was running earlier, but this error started after I added dependencies for spring-cloud-stream.I tried removing spring-fox dependency but it only removed the nested exception.
The complete error after removing spring-fox dependency:
ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
The complete pom.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.foo.bar.application</groupId>
<artifactId>application-reviews-manager</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>generic-name</name>
<description>Manager</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<application.utils.version>1.0.0</application.utils.version>
<application.utils.build.number>SNAPSHOT</application.utils.build.number>
<application.rnr.repositories.version>1.0.0</application.rnr.repositories.version>
<application.rnr.repositories.build.number>SNAPSHOT</application.rnr.repositories.build.number>
<dcp.config.version>0.0.1</dcp.config.version>
<dcp.config.build.number>SNAPSHOT</dcp.config.build.number>
<aspectj.version>1.8.9</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>com.foo.bar.application</groupId>
<artifactId>application-rnr-repositories</artifactId>
<version>${application.rnr.repositories.version}-${application.rnr.repositories.build.number}</version>
</dependency>
<dependency>
<groupId>com.foo.bar.application</groupId>
<artifactId>application-utils</artifactId>
<version>${application.utils.version}-${application.utils.build.number}</version>
</dependency>
<dependency>
<groupId>com.foo.dcp.commons.config</groupId>
<artifactId>dcp-config-client</artifactId>
<version>${dcp.config.version}-${dcp.config.build.number}</version>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>5.6.3</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>5.6.3</version>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>1.58</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.elasticsearch.test</groupId>
<artifactId>framework</artifactId>
<version>5.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
I'm just a starter in spring-cloud-stream, so any help would be appreciated.
Edit:
We found out that the mistake is in the way or place the annotation
#EnableBinding is used.
The relevant pieces of codes are:
Application.java
package com.foo.bar;
import com.foo.bar.configuration.FooStreams;
import com.foo.bar.configuration.BarStreams;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.context.annotation.Bean;
import com.externalpackage.config.client.AppConfiguration;
import com.foo.bar.storage.repository.CustomElasticRestClient;
#SpringBootApplication
#EnableBinding({FooStreams.class, BarStreams.class})
public class FooApplication {
public static void main(String[] args) {
SpringApplication.run(FooApplication.class, args);
}
#Bean
public AppConfiguration appConfiguration() {
return AppConfiguration.instance();
}
#Bean
public CustomElasticRestClient highLevelElasticClient(AppConfiguration appConfiguration) throws Exception {
return new CustomElasticRestClient(appConfiguration);
}
}
FooStreams.java
package com.foo.bar.configuration;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
public interface FooStreams {
String OUTPUT = "foo-out";
#Output(value = OUTPUT)
MessageChannel postFooToOutChanel();
}
BarStreams.java
package com.tesco.foo.bar.configuration;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
public interface BarStreams {
String OUTPUT = "bar-out";
#Output(value = OUTPUT)
MessageChannel postBarToOutChanel();
}
KafkaPublisherService.java:
package com.foo.bar.service;
import com.foo.bar.configuration.FooStreams;
import com.foo.bar.configuration.BarStreams;
import com.foo.bar.domain.Foo;
import com.foo.bar.domain.Bar;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.MimeTypeUtils;
#Service
#Slf4j
public class KafkaPublisherService {
#Autowired
private BarStreams barStreams;
#Autowired
private FooStreams fooStreams;
public void sendBar(final Bar bar) {
log.info("Publishing bar to kafka {}", bar);
MessageChannel messageChannel = barStreams.postBarToOutChanel();
messageChannel.send(MessageBuilder
.withPayload(bar)
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
.build());
}
public void sendFoo(final Foo foo) {
log.info("Publishing foo to kafka {}", foo);
MessageChannel messageChannel = fooStreams.postFooToOutChanel();
messageChannel.send(MessageBuilder
.withPayload(foo)
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
.build());
}
}
application.properties
spring.cloud.stream.kafka.binder.brokers=localhost:9092
spring.cloud.stream.bindings.foo-out.destination=feedback
spring.cloud.stream.bindings.foo-out.contentType=application/json
spring.cloud.stream.bindings.bar-out.destination=review
spring.cloud.stream.bindings.bar-out.contentType=application/json