I am working on a project, i have completed but issue is in project i have to write integration testing code.
This is the controller
#PostMapping("/newgame")
public ResponseEntity<Players> beginNewGame(#RequestBody Players players) {
Players savedPersion = playerService.beginNewGame(players);
return savedPersion!=null ? ResponseEntity.ok(savedPersion):
(ResponseEntity<Players>) ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
}
And this is service.
#Override
public Players beginNewGame(Players players) {
//new game state
GameState gameState =new GameState();
gameState.setWinner("null");
GameState save = gameStateRepositery.save(gameState);
//new score
Score score = new Score();
score.setGameId(save.getId());
Score savedScore = scoreRepositery.save(score);
players.setScoreId(savedScore.getId());
players.setGameId(save.getId());
Players savedPlayers=null;
savedPlayers= playersRepositery.save(players);
System.out.println(savedScore.getGameId()+"ksdjfkjskn");
return savedPlayers;
}
And if i hit the endpoints with proper required parameters, the is
working fine, and return me.
{
"gameId": 57,
"id": 1,
"playerOne": "vinitSaini",
"playerTwo": "anonymousKal",
"scoreId": 58
}
This is the testing code, how i can check what the response is
returning.
#ExtendWith(SpringExtension.class)
#SpringBootTest
#AutoConfigureMockMvc
public class PlayersIntTest {
#Autowired
private MockMvc mockMvc;
#Autowired
private ObjectMapper objectMapper;
#Autowired
private PlayersRepositery playersRepositery;
#Test
void newGame() throws Exception {
//mockMvc.perform(post("/api/{forumId}/register", 42L)
mockMvc.perform(post("/api/newgame")
.contentType("application/json")
.content(objectMapper.writeValueAsString(players)))
.andExpect(status().isOk());
}
So please help me to write integration testing.
You can convert the response in JSON and check values of JSON properties using MockMvcResultMatchers
mockMvc.perform(post("/api/newgame")
.contentType("application/json")
.content(objectMapper.writeValueAsString(players)))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content()
.contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.jsonPath("$.gameId")
.value(57))
.andExpect(MockMvcResultMatchers.jsonPath("$.id")
.value(1))
.andExpect(MockMvcResultMatchers.jsonPath("$.playerOne")
.value("vinitSaini"))
.andExpect(MockMvcResultMatchers.jsonPath("$.playerTwo")
.value("anonymousKal"))
.andExpect(MockMvcResultMatchers.jsonPath("$.scoreId")
.value(58));
#Test
void newGame() throws Exception {
//mockMvc.perform(post("/api/{forumId}/register", 42L)
ResultActions resultActions = mockMvc.perform(post("/api/newgame")
.contentType("application/json")
.content(objectMapper.writeValueAsString(players)))
.andExpect(status().isOk());
String responseInJson = resultActions.andReturn().getResponse().getContentAsString();
Players responseObj = objectMapper.readValue(responseInJson, Players.class);
Assert.assertNotNull(responseObj);
// You can add all asserts here
}
Related
I have a problem when adding new test. And the problem is I think related to #DirtiesContext. I tried removing and adding it but nothing works in combination. Test 1 is using Application Context as well.
the following two are running together and no issue.
Test 1
#ActiveProfiles({"aws", "local"})
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UnauthorizedControllerTest {
private static final Logger LOGGER = LoggerFactory.getLogger(UnauthorizedControllerTest.class);
#Autowired
private TestRestTemplate testRestTemplate;
#LocalServerPort
private int port;
#Autowired
private ApplicationContext context;
private Map<Class<?>, List<String>> excludedMethodsPerController;
#Before
public void setUp() {
excludedMethodsPerController = excludedMethodsPerController();
}
#Test
public void contextStarts() {
assertNotNull(context);
}
#Test
public void controllerCall_WithoutAuthorization_ReturnsUnauthorized() {
Map<String, Object> controllerBeans = context.getBeansWithAnnotation(Controller.class);
for (Object controllerInstance : controllerBeans.values()) {
LOGGER.info("Checking controller {}", controllerInstance);
checkController(controllerInstance);
}
}
public void checkController(Object controllerInstance) {
// Use AopUtils for the case that spring wraps the controller in a proxy
Class<?> controllerClass = AopProxyUtils.ultimateTargetClass(controllerInstance);
Method[] allMethods = controllerClass.getDeclaredMethods();
for (Method method : allMethods) {
LOGGER.info("Checking method: {}", method.getName());
if (!isCallable(controllerClass, method)) {
continue;
}
String urlPrefix = urlPrefix(controllerClass);
Mapping mapping = Mapping.of(method.getAnnotations());
for (String url : mapping.urls) {
for (RequestMethod requestMethod : mapping.requestMethods) {
ResponseEntity<String> exchange = exchange(urlPrefix + url, requestMethod);
String message = String.format("Failing %s.%s", controllerClass.getName(), method.getName());
assertEquals(message, HttpStatus.UNAUTHORIZED, exchange.getStatusCode());
}
}
}
}
private ResponseEntity<String> exchange(String apiEndpoint, RequestMethod requestMethod) {
return testRestTemplate.exchange(url(replacePathVariables(apiEndpoint)), HttpMethod.resolve(requestMethod.name()), null, String.class);
}
private String urlPrefix(Class<?> aClass) {
if (!aClass.isAnnotationPresent(RequestMapping.class)) {
return "";
}
RequestMapping annotation = aClass.getAnnotation(RequestMapping.class);
return annotation.value()[0];
}
private String url(String url) {
return "http://localhost:" + port + url;
}
private boolean isCallable(Class<?> controller, Method method) {
return Modifier.isPublic(method.getModifiers())
&& !isExcluded(controller, method)
&& !isExternal(controller);
}
private boolean isExcluded(Class<?> controller, Method method) {
List<String> excludedMethodsPerController = this.excludedMethodsPerController.getOrDefault(controller, new ArrayList<>());
return excludedMethodsPerController.contains(method.getName());
}
private boolean isExternal(Class<?> controller) {
return controller.getName().startsWith("org.spring");
}
private String replacePathVariables(String url) {
return url.replaceAll("\\{[^\\/]+}", "someValue");
}
/**
* There must be a really good reason to exclude the method from being checked.
*
* #return The list of urls that must not be checked by the security
*/
private static Map<Class<?>, List<String>> excludedMethodsPerController() {
Map<Class<?>, List<String>> methodPerController = new HashMap<>();
methodPerController.put(AuthenticationController.class, Collections.singletonList("generateAuthorizationToken"));
methodPerController.put(SystemUserLoginController.class, Arrays.asList("systemUserLogin", "handleException"));
methodPerController.put(ValidationController.class, Collections.singletonList("isValid"));
return methodPerController;
}
}
Test 2
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles({"aws", "local"})
public class RoleAdminControllerAuditTest {
private static final String DOMAIN_NAME = "testDomain";
private static final String APP_NAME_1 = "testApp_1";
private static final String APP_NAME_2 = "testApp_2";
private static final String ROLE_NAME = "testRole";
private static final String USER_NAME = "testUser";
#Autowired
AuditRepository auditRepository;
#Autowired
RoleAdminController roleAdminController;
#MockBean
RoleAdminService roleAdminService;
#MockBean
RoleAdminInfoBuilder infoBuilder;
#MockBean
AppInfoBuilder appInfoBuilder;
#MockBean
BoundaryValueService boundaryValueService;
#MockBean
RoleService roleService;
#MockBean
private SecurityService securityService;
private static final String URS_USER = "loggedInUser";
private static final String BOUNDARY_VALUE_KEY = "11";
private static final String BOUNDARY_VALUE_NAME = "Schulenberg";
private String auditEventDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
#BeforeClass
public static void setupTestEnv() {
// https://github.com/localstack/localstack/issues/592
System.setProperty("com.amazonaws.sdk.disableCbor", "true");
}
#Before
public void setUp() throws Exception {
auditRepository.clean();
when(securityService.getLoggedInUser()).thenReturn(new TestHelper.FakeUser(URS_USER));
//when(roleService.addRoleToApp(any(), any(), eq(ROLE_NAME))).thenReturn(TestHelper.initRole(ROLE_NAME));
when(boundaryValueService.findBoundaryValueById(eq(123L))).thenReturn(initBoundaryValue(BOUNDARY_VALUE_KEY, BOUNDARY_VALUE_NAME));
when(boundaryValueService.findBoundaryValueById(eq(666L))).thenReturn(initBoundaryValue(BOUNDARY_VALUE_KEY, BOUNDARY_VALUE_NAME));
}
#Test
public void addUserAsRoleAdminLogged() throws UserIsAlreadyRoleAdminException, RoleNotFoundException, BoundaryValueNotFoundException {
User user = initUser(USER_NAME);
List<RoleAdminInfo> roleAdminInfos = getRoleAdminInfos();
roleAdminController.addUserAsRoleAdmin(user, roleAdminInfos);
List<String> result = auditRepository.readAll();
assertEquals("some data", result.toString());
}
#Test
public void removeUserAsRoleAdminLogged() throws RoleNotFoundException, BoundaryValueNotFoundException {
User user = initUser(USER_NAME);
Long roleId = Long.valueOf(444);
Role role = initRole("test-role");
role.setApp(initApp("test-app"));
role.setDomain(initDomain("test-domain"));
when(roleService.getRoleByIdOrThrow(roleId)).thenReturn(role);
roleAdminController.removeUserAsRoleAdmin(user, roleId, Long.valueOf(666));
List<String> result = auditRepository.readAll();
assertEquals("some data", result.toString());
}
#Test
public void removeRoleAdminPermission() throws RoleNotFoundException, BoundaryValueNotFoundException {
User user = initUser(USER_NAME);
List<RoleAdminInfo> roleAdminInfos = getRoleAdminInfos();
roleAdminController.removeRoleAdminPermission(user, roleAdminInfos);
List<String> result = auditRepository.readAll();
assertEquals(1, result.size());
assertEquals("some data", result.toString());
}
private List<RoleAdminInfo> getRoleAdminInfos() {
RoleAdminInfo info1 = initRoleAdminInfo(DOMAIN_NAME, ROLE_NAME, APP_NAME_1);
RoleAdminInfo info2 = initRoleAdminInfo(DOMAIN_NAME, ROLE_NAME, APP_NAME_2);
info1.setBoundaryValueId(123L);
info1.setBoundaryValueKey(BOUNDARY_VALUE_KEY);
info1.setBoundaryValueName(BOUNDARY_VALUE_NAME);
return Arrays.asList(info1, info2);
}
}
Test 3 (newly added one)
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = FlywayConfig.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
#ActiveProfiles({"aws", "local"})
public class BoundaryValueDeltaControllerTest {
private static final String API_V1 = "/api/v1/";
#Autowired
TestRestTemplate testRestTemplate;
#Autowired
private DomainBuilder domainBuilder;
#Autowired
private AppBuilder appBuilder;
#Autowired
private UserBuilder userBuilder;
#Autowired
private DomainAdminBuilder domainAdminBuilder;
#Autowired
private BoundarySetBuilder boundarySetBuilder;
#MockBean
private LoginUserProvider loginUserProvider;
#MockBean
private LoginTokenService loginTokenService;
#MockBean
private BoundaryServiceAdapter serviceAdapter;
#LocalServerPort
private int port;
LoginUserInfo loggedInUser;
#Before
public void setUp() {
clear();
}
#After
public void tearDown() {
clear();
}
#Test
public void updateBoundaryValuesFromApi() throws UrsBusinessException {
Domain domain = domainBuilder.persist();
App app = appBuilder.persist(domain);
BoundarySet boundarySet = boundarySetBuilder.persist(domain);
User user = userBuilder.persist(domain.getAuthor().getUsername());
aLoggedInUser(domain.getAuthor().getUsername());
domainAdminBuilder.persist(user, domain);
mockReadInfoFromApiUsingApp();
ResponseEntity<String> response = callUpdateBoundaryValuesFromApi(domain, boundarySet, app);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
}
private void mockReadInfoFromApiUsingApp() throws UrsBusinessException {
BoundaryValueInfo boundaryValueInfo = new BoundaryValueInfo();
boundaryValueInfo.setBoundaryValueId(10L);
boundaryValueInfo.setBoundaryValueKey("boundaryValueKey");
boundaryValueInfo.setBoundaryValueName("boundaryValuename");
when(serviceAdapter.readInfoFromApiUsingApp(any(), any(), any())).thenReturn(new BoundaryValueInfo[]{boundaryValueInfo});
}
private ResponseEntity<String> callUpdateBoundaryValuesFromApi(Domain domain, BoundarySet boundarySet, App app) {
String url = url(API_V1 + "domains/" + domain.getName() + "/boundarysets/" + boundarySet.getBoundarySetName() + "/app/" + app.getName()+ "/updatefromapi/");
return testRestTemplate.exchange(url,HttpMethod.GET, null, String.class);
}
private String url(String url) {
return "http://localhost:" + port + url;
}
private void aLoggedInUser(String username) {
Claims claims = Jwts.claims();
claims.put("username", username);
loggedInUser = LoginUserInfo.parse(claims);
when(loginUserProvider.getLoggedInUser()).thenReturn(loggedInUser);
when(loginTokenService.parseToken(any())).thenReturn(loggedInUser);
}
private void clear() {
appBuilder.deleteAll();
boundarySetBuilder.deleteAll();
domainAdminBuilder.deleteAll();
domainBuilder.deleteAll();
userBuilder.deleteAll();
}
}
Flyway config
#TestConfiguration
public class FlywayConfig {
#Bean
public FlywayMigrationStrategy clean() {
return flyway -> {
flyway.clean();
flyway.migrate();
};
}
}
And I am getting below exception while running all together.
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java.....
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.internal.exception.FlywaySqlException:
Unable to obtain connection from database: Too many connections
---------------------------------------------------------------
SQL State : 08004
Error Code : 1040
Message : Too many connections
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1762)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
... 49 more
Caused by: org.flywaydb.core.internal.exception.FlywaySqlException:
Unable to obtain connection from database: Too many connections
I am struggling since yesterday's and you might find duplicate but I tried to add the more details today. please guide me here.
you must add the configuration for flyway
flyway.url=jdbc:postgresql://xxx.eu-west-2.rds.amazonaws.com:5432/xxx
flyway.user=postgres
flyway.password=xxx
I have started an instance of EmbeddedKafka in a JUnit test. I can read the records that I have pushed to my stream correctly in my application, but one thing I have noticed is that I only have one partition per topic. Can anyone explain why?
In my application I have the following:
List<PartitionInfo> partitionInfos = consumer.partitionsFor(topic);
This returns a list with one item. When running against local Kafka with 3 partitions, it returns a list with 3 items as expected.
And my test looks like:
#RunWith(SpringRunner.class)
#SpringBootTest
#EmbeddedKafka(partitions = 3)
#ActiveProfiles("inmemory")
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
#TestPropertySource(
locations = "classpath:application-test.properties",
properties = {"app.onlyMonitorIfDataUpdated=true"})
public class MonitorRestKafkaIntegrationTest {
#Autowired
private EmbeddedKafkaBroker embeddedKafkaBroker;
#Value("${spring.embedded.kafka.brokers}")
private String embeddedBrokers;
#Autowired
private WebApplicationContext wac;
#Autowired
private JsonUtility jsonUtility;
private MockMvc mockMvc;
#Before
public void setup() {
mockMvc = webAppContextSetup(wac).build();
UserGroupInformation.setLoginUser(UserGroupInformation.createRemoteUser("dummyUser"));
}
private ResultActions interactiveMonitoringREST(String eggID, String monitoringParams) throws Exception {
return mockMvc.perform(post(String.format("/eggs/%s/interactive", eggID)).contentType(MediaType.APPLICATION_JSON_VALUE).content(monitoringParams));
}
#Test
#WithMockUser("super_user")
public void testEmbeddedKafka() throws Exception {
Producer<String, String> producer = getKafkaProducer();
sendRecords(producer, 3);
updateConn();
interactiveMonitoringREST(EGG_KAFKA, monitoringParams)
.andExpect(status().isOk())
.andDo(print())
.andExpect(jsonPath("$.taskResults[0].resultDetails.numberOfRecordsProcessed").value(3))
.andExpect(jsonPath("$.taskResults[0].resultDetails.numberOfRecordsSkipped").value(0));
}
private void sendRecords(Producer<String, String> producer, int records) {
for (int i = 0; i < records; i++) {
String val = "{\"auto_age\":" + String.valueOf(i + 10) + "}";
producer.send(new ProducerRecord<>(testTopic, String.valueOf(i), val));
}
producer.flush();
}
private Producer<String, String> getKafkaProducer() {
Map<String, Object> prodConfigs = new HashMap<>(KafkaTestUtils.producerProps(embeddedKafkaBroker));
return new DefaultKafkaProducerFactory<>(prodConfigs, new StringSerializer(), new StringSerializer()).createProducer();
}
private void updateConn() throws Exception {
String conn = getConnectionREST(CONN_KAFKA).andReturn().getResponse().getContentAsString();
ConnectionDetail connectionDetail = jsonUtility.fromJson(conn, ConnectionDetail.class);
connectionDetail.getDetails().put(ConnectionDetailConstants.CONNECTION_SERVER, embeddedBrokers);
String updatedConn = jsonUtility.toJson(connectionDetail);
updateConnectionREST(CONN_KAFKA, updatedConn).andExpect(status().isOk());
}
}
You need to tell the broker to pre-create the topics...
#SpringBootTest
#EmbeddedKafka(topics = "foo", partitions = 3)
class So57481979ApplicationTests {
#Test
void testPartitions(#Autowired KafkaAdmin admin) throws InterruptedException, ExecutionException {
AdminClient client = AdminClient.create(admin.getConfig());
Map<String, TopicDescription> map = client.describeTopics(Collections.singletonList("foo")).all().get();
System.out.println(map.values().iterator().next().partitions().size());
}
}
Or set the num.partitions broker property if you want the broker to auto-create the topics for you on first use.
We should probably automatically do that, based on the partitions property.
I found bootstrapServersProperty is important in #EmbeddedKafka, which is used to populate the property in the application-test.yml, which then can be used to create consumers/listener containers.
I'm new to Spring Boot and Testing.
tl;dr How do I replace a #MockBean controller with the actual controller, in a spring boot application so that I can test that the controller is working instead of just testing that my objects are output correctly?
I'm writing a gradle managed API with dependencies (from build.gradle):
// Spring Boot (2.0.5 Release)
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-hateoas')
compile('org.springframework.boot:spring-boot-starter-web')
runtime('org.springframework.boot:spring-boot-devtools')
// Testing
testImplementation('org.junit.jupiter:junit-jupiter-api:5.3.1')
testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.3.1')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile("org.assertj:assertj-core:3.11.1")
testCompile 'org.mockito:mockito-core:2.+'
I've got an API controller class with the following relevant code:
#Controller
public class ObjectivesApiController extends AbstractRestHelperFunctionality implements ObjectivesApi {
protected ObjectivesApiController(
UserRepository userRepository,
CompaniesRepository companiesRepository,
TeamsRepository teamsRepository,
ProjectsRepository projectsRepository,
OdiAssessmentRepository odiAssessmentRepository,
OdiCustomerRatingRepository odiCustomerRatingRepository,
OdiTechRatingRepository odiTechRatingRepository,
OdiValueRatingRepository odiValueRatingRepository,
ObjectivesRepository objectivesRepository,
KeyResultRepository keyResultRepository) {
super(
userRepository,
companiesRepository,
teamsRepository,
projectsRepository,
odiAssessmentRepository,
odiCustomerRatingRepository,
odiTechRatingRepository,
odiValueRatingRepository,
objectivesRepository,
keyResultRepository);
}
public ResponseEntity<KeyResult> createKeyResult(#ApiParam(value = "id", required = true) #PathVariable("id") Long id, #ApiParam(value = "keyResult", required = true) #Valid #RequestBody KeyResult keyResultDTO) {
KeyResult keyResult = KeyResultBuilder
.aKeyResult()
.withDescription(keyResultDTO.getDescription())
.withCompleted(keyResultDTO.getCompleted())
.build();
Objective parentObjective = objectivesRepository.findByObjectiveId(id);
parentObjective.addKeyResult(keyResult);
keyResultRepository.save(keyResult);
objectivesRepository.save(parentObjective);
return new ResponseEntity<KeyResult>(HttpStatus.CREATED);
}
public ResponseEntity<Objective> createObjective(#ApiParam(value = "objective", required = true) #Valid #RequestBody Objective objectiveDTO) {
Objective objective = ObjectiveBuilder
.anObjective()
.withDescription(objectiveDTO.getDescription())
.withCompleted(objectiveDTO.getCompleted())
.withKeyResults(objectiveDTO.getKeyResults())
.build();
objective.getKeyResults().forEach(keyResultRepository::save);
objectivesRepository.save(objective);
return new ResponseEntity<Objective>(HttpStatus.CREATED);
}
public ResponseEntity<Void> deleteAllLinkedKeyResults(#ApiParam(value = "id", required = true) #PathVariable("id") Long id) {
Objective subjectObjective = objectivesRepository.findByObjectiveId(id);
subjectObjective.getKeyResults().clear();
objectivesRepository.save(subjectObjective);
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}
public ResponseEntity<Void> deleteObjective(#ApiParam(value = "id", required = true) #PathVariable("id") Long id) {
objectivesRepository.delete(objectivesRepository.findByObjectiveId(id));
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}
public ResponseEntity<Void> deleteOneKeyResult(#ApiParam(value = "the id of the objective you want key results for", required = true) #PathVariable("objectiveId") Long objectiveId, #ApiParam(value = "the id of the key result", required = true) #PathVariable("keyResultId") Long keyResultId) {
Objective subjectObjective = objectivesRepository.findByObjectiveId(objectiveId);
KeyResult keyResult = keyResultRepository.findByKeyResultId(keyResultId);
subjectObjective.removeKeyResult(keyResult);
objectivesRepository.save(subjectObjective);
keyResultRepository.delete(keyResult);
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}
public ResponseEntity<List<Objective>> getAllObjectives() {
List<Objective> allObjectives = objectivesRepository.findAll();
return new ResponseEntity<List<Objective>>(allObjectives, HttpStatus.OK);
}
public ResponseEntity<List<KeyResult>> getKeyResultsForObjective(#ApiParam(value = "id", required = true) #PathVariable("id") Long id) {
Objective subjectObjective = objectivesRepository.findByObjectiveId(id);
List<KeyResult> allKeyResults = subjectObjective.getKeyResults();
return new ResponseEntity<List<KeyResult>>(allKeyResults, HttpStatus.OK);
}
public ResponseEntity<Objective> getObjective(#ApiParam(value = "id", required = true) #PathVariable("id") Long id) {
Objective subjectObjective = objectivesRepository.findByObjectiveId(id);
return new ResponseEntity<Objective>(subjectObjective, HttpStatus.OK);
}
public ResponseEntity<KeyResult> getKeyResultForObjective(#ApiParam(value = "the id of the objective you want key results for", required = true) #PathVariable("objectiveId") Long objectiveId, #ApiParam(value = "the id of the key result", required = true) #PathVariable("keyResultId") Long keyResultId) {
Objective subjectObjective = objectivesRepository.findByObjectiveId(objectiveId);
KeyResult subjecKeyResult = subjectObjective.getKeyResults().stream()
.filter(KeyResult -> keyResultId.equals(KeyResult.getKeyResultId()))
.findFirst()
.orElse(null);
return new ResponseEntity<KeyResult>(subjecKeyResult, HttpStatus.OK);
}
public ResponseEntity<Objective> updateObjective(#ApiParam(value = "id", required = true) #PathVariable("id") Long id, #ApiParam(value = "objective", required = true) #Valid #RequestBody Objective objectiveDTO) {
Objective existingObjective = objectivesRepository.findByObjectiveId(id);
Objective objective = ObjectiveBuilder
.anObjective()
.withObjectiveId(existingObjective.getObjectiveId())
.withDescription(objectiveDTO.getDescription())
.withCompleted(objectiveDTO.getCompleted())
.withKeyResults(objectiveDTO.getKeyResults())
.build();
objective.getKeyResults().forEach(keyResultRepository::save);
objectivesRepository.save(objective);
return new ResponseEntity<Objective>(HttpStatus.NO_CONTENT);
}
public ResponseEntity<KeyResult> updateKeyResult(#ApiParam(value = "the id of the objective you want key results for", required = true) #PathVariable("objectiveId") Long objectiveId, #ApiParam(value = "the id of the key result", required = true) #PathVariable("keyResultId") Long keyResultId, #ApiParam(value = "keyResult", required = true) #Valid #RequestBody KeyResult keyResultDTO) {
if (objectivesRepository.existsById(objectiveId) && keyResultRepository.existsById(keyResultId)) {
Objective subjectObjective = objectivesRepository.findByObjectiveId(objectiveId);
KeyResult subjecKeyResult = subjectObjective.getKeyResults().stream()
.filter(KeyResult -> keyResultId.equals(KeyResult.getKeyResultId()))
.findFirst()
.orElse(null);
KeyResult updatedKeyResult = KeyResultBuilder
.aKeyResult()
.withKeyResultId(subjecKeyResult.getKeyResultId())
.withDescription(keyResultDTO.getDescription())
.withCompleted(keyResultDTO.getCompleted())
.build();
keyResultRepository.save(updatedKeyResult);
Collections.replaceAll(subjectObjective.getKeyResults(), subjecKeyResult, updatedKeyResult);
objectivesRepository.save(subjectObjective);
}
return new ResponseEntity<KeyResult>(HttpStatus.NO_CONTENT);
}
}
For context on this class, all the AbstractRestHelper super class is doing, is creating singletons of my repositories, which are then .. field injected (unsure if this is the right term) in to the controller. This pattern is repeated across all controllers hence the clutter.
The API being implemented is a Swagger 2 API interface that keeps this controller free of annotations where possible.
The final piece is the test class. This is the core of my question.
#ExtendWith(SpringExtension.class)
#WebMvcTest(ObjectivesApiController.class)
class ObjectivesApiControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private ObjectivesApiController objectivesApiControllerMock;
#BeforeEach
void setUp() {
}
#AfterEach
void tearDown() {
}
#Test
void getAllObjectives() throws Exception {
// Create two objects to test with:
Objective testObjective1 = ObjectiveBuilder
.anObjective()
.withObjectiveId(1L)
.withDescription("Test Objective")
.withCompleted(false)
.build();
Objective testObjective2 = ObjectiveBuilder
.anObjective()
.withObjectiveId(2L)
.withDescription("Test Objective")
.withCompleted(true)
.build();
List<Objective> testList = new ArrayList<Objective>();
testList.add(testObjective1);
testList.add(testObjective2);
// Set expectations on what should be found:
when(objectivesApiControllerMock.getAllObjectives()).thenReturn(new ResponseEntity<List<Objective>>(testList, HttpStatus.OK));
// Carry out the mocked API call:
mockMvc.perform(get("/objectives"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].objectiveId", is(1)))
.andExpect(jsonPath("$[0].description", is("Test Objective")))
.andExpect(jsonPath("$[0].completed", is(false)))
.andExpect(jsonPath("$[1].objectiveId", is(2)))
.andExpect(jsonPath("$[1].description", is("Test Objective")))
.andExpect(jsonPath("$[1].completed", is(true)));
// Validate the response is what we expect:
verify(objectivesApiControllerMock, times(1)).getAllObjectives();
verifyNoMoreInteractions(objectivesApiControllerMock);
}
#Test
void getKeyResultsForObjective() throws Exception {
KeyResult testKeyResultWithParentObjective1 = KeyResultBuilder
.aKeyResult()
.withKeyResultId(1L)
.withCompleted(false)
.withDescription("My parent Key Result is 1")
.build();
KeyResult testKeyResultWithParentObjective2 = KeyResultBuilder
.aKeyResult()
.withKeyResultId(2L)
.withCompleted(true)
.withDescription("My parent Key Result is 1")
.build();
Objective testObjectiveWithKeyResults = ObjectiveBuilder
.anObjective()
.withObjectiveId(1L)
.withDescription("Test Objective")
.withKeyResults(new ArrayList<KeyResult>())
.withCompleted(false)
.build();
testObjectiveWithKeyResults.addKeyResult(testKeyResultWithParentObjective1);
testObjectiveWithKeyResults.addKeyResult(testKeyResultWithParentObjective2);
when(objectivesApiControllerMock.getKeyResultsForObjective(1L)).thenReturn(new ResponseEntity<List<KeyResult>>(testObjectiveWithKeyResults.getKeyResults(), HttpStatus.OK));
mockMvc.perform(get("/objectives/1/keyresult"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].keyResultId", is(1)))
.andExpect(jsonPath("$[0].description", is("My parent Key Result is 1")))
.andExpect(jsonPath("$[0].completed", is(false)))
.andExpect(jsonPath("$[1].keyResultId", is(2)))
.andExpect(jsonPath("$[1].description", is("My parent Key Result is 1")))
.andExpect(jsonPath("$[1].completed", is(true)));
}
}
My question is this:
Having mocked the objective controller using Mockito to validate that my objects are being formed properly, I now want to do the same thing but instead of mocking, I want to actually test the controller.
What do you think is the most naive way of getting this to work (I can refactor later). The resources I've search through either use different versions of Junit or rely on mockito rather than the actual controller.
Nothing fits quite right - since the controller is mocked, I'm not actually covering any code, and so the tests are worthless right? The only thing I'm looking at is that the objects are formed properly, where I now need to check that the controller is functioning as it should, AND are returning well formed objects.
Has anyone done anything simillar? What approaches do you use to manage the testing of field injected controllers?
Any advice on this would be hugely appreciated. I'd love to learn how people working on production grade applications are handling the testing of Spring Boot Apps with Controllers, Repos, etc.
Thanks so much!
You could use #SpyBean. That way you can both use it as it is or mock some calls. https://www.baeldung.com/mockito-spy
I am new to Junit. Recently, I need add some test function for a spring web project.
So I add a new project only for testing.
Firstly, I add a test case for testing ADServiceImpl, and following is my test code.
#Test
public void test() {
ADServiceImpl service = new ADServiceImpl();
UserInfo info = service.getUserInfo("admin", "123456");
assertEquals("Result", "00", info.getStatus().getCode());
}
After I run the test and got a error is that 'endpoint' is null. But 'endpoint' is setting by spring #Resource(name = "adEndpoint") from xml configuration.
How can I deal with this problem?? Or is there other recommend for spring web project testing? Thank you so much!
#Service("ADService")
public class ADServiceImpl implements ADService {
private final static Logger logger = Logger.getLogger(ADServiceImpl.class);
#Resource(name = "adEndpoint")
private String endpoint;
public UserInfo getUserInfo(String acc, String pwd) throws JAXBException, RemoteException {
if (StringUtils.isBlank(endpoint)) {
logger.error("***** AD Endpoint is blank, please check sysenv.ad.endpoint param ******");
}
ADSoapProxy proxy = new ADSoapProxy();
proxy.setEndpoint(endpoint);
logger.debug("***** AD endpoint:" + endpoint + "******");
String xml = proxy.userInfo(acc, pwd);
StringReader reader = new StringReader(xml);
JAXBContext jaxbContext = JAXBContext.newInstance(UserInfo.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
return (UserInfo) jaxbUnmarshaller.unmarshal(reader);
}
}
When creating Unit Tests that requires Spring to be running you need to add the following to your unit test class. For example:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MySpringApp.class)
public MyTestClass{
#Test
...
}
More info here
I try to create a soap UI WSDL Mock Service using the soapUI API. But there seems to be no documentation of the source code.
Has anyone done this before or something in that direction?
Ok, I can now answer myself ... :)
I created a unit test for this task:
private static WsdlProjectFactory wsdlProjectFactory;
private static WsdlInterfaceFactory wsdlInterfaceFactory;
#BeforeClass
public static void createFactories(){
wsdlProjectFactory = new WsdlProjectFactory();
wsdlInterfaceFactory = new WsdlInterfaceFactory();
}
#Before
public void deleteCreatedFiles() {
new File("global-groovy.log").delete();
new File("soapui-errors.log").delete();
new File("soapui.log").delete();
new File("test.xml").delete();
}
private WsdlProject project;
#Before
public void createProject() throws XmlException, IOException, SoapUIException {
project = wsdlProjectFactory.createNew();
}
#Test #Ignore
public void testWSDLInterfaceImporting() throws SoapUIException {
int interfaceCount = project.getInterfaceCount();
assertThat("newly created project has no interfaces", interfaceCount, is(equalTo(0)));
WsdlInterface[] importWsdl = wsdlInterfaceFactory.importWsdl(project, "wsdls/SimpleUseCasesellerbtainitialbtexampleMasterClient.wsdl", false);
interfaceCount = project.getInterfaceCount();
assertThat("newly created project has 1 interface", interfaceCount, is(equalTo(1)));
}
#Test
public void testMockCreation() throws XmlException, IOException, SoapUIException {
int mockCount = project.getMockServiceCount();
assertThat("newly created project has no mocks", mockCount, is(equalTo(0)));
WsdlInterface[] importWsdl = wsdlInterfaceFactory.importWsdl(project, "wsdls/SimpleUseCasesellerbtainitialbtexampleMasterClient.wsdl", false);
WsdlMockService service = project.addNewMockService("newMockService");
service.addNewMockOperation(importWsdl[0].getOperationAt(0));
project.saveAs("test.xml");
mockCount = project.getMockServiceCount();
assertThat("project has exactly one mock", mockCount, is(1));
}