I want to write a contract using spring cloud contract in producer API.
My controller looks like :
#PostMapping(value = "/employee")
public ResponseEntity<Employee> getEmployee(#RequestBody Request employeeRequest) {
Optional<Employee> employee = employeeService.getEmployee(employeeRequest);
if(employee.isPresent()){
return ResponseEntity.status(HttpStatus.OK).
contentType(MediaType.APPLICATION_JSON).body(employee.get());
}else{
return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Request class :
#Setter
#Getter
public class Request {
private Integer id;
}
Response (Employee) class :
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
public class Employee {
public Integer id;
public String fname;
public String lname;
public Double salary;
public String gender;
}
Dsl written in groovy :
import org.springframework.cloud.contract.spec.Contract
Contract.make {
request {
method 'POST'
url '/employee'
headers {
contentType(applicationJson())
}
body(
id : 25
)
}
response {
status 200
headers {
contentType(applicationJson())
}
body("""
{
"id":25,
"fname":"sara",
"lname":"ahmadi",
"salary":"25000.00",
"gender":"F"
}
""")
}
}
Plugin in pom.xml :
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>2.2.3.RELEASE</version>
<extensions>true</extensions>
<configuration>
<baseClassForTests>example.co.ir.contractproducer.BaseTestClass</baseClassForTests>
<testFramework>JUNIT5</testFramework>
</configuration>
</plugin>
And BaseTestClass :
import io.restassured.config.EncoderConfig;
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import io.restassured.module.mockmvc.config.RestAssuredMockMvcConfig;
import isc.co.ir.contractproducer.controller.EmployeeController;
import isc.co.ir.contractproducer.model.Employee;
import isc.co.ir.contractproducer.model.Request;
import isc.co.ir.contractproducer.service.EmployeeService;
import org.junit.jupiter.api.BeforeEach;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder;
import java.util.Optional;
#SpringBootTest
public class BaseTestClass {
#Autowired
private EmployeeController employeeController;
#MockBean
private EmployeeService employeeService;
#BeforeEach
public void setup(){
Employee employee2=new Employee(25,"Adam","Brown",25000.0,"F");
Request request = new Request();
request.setId(25);
Mockito.when(employeeService.getEmployee(request)).thenReturn(Optional.of(employee2));
EncoderConfig encoderConfig = new EncoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false);
RestAssuredMockMvc.config = new RestAssuredMockMvcConfig().encoderConfig(encoderConfig);
StandaloneMockMvcBuilder standaloneMockMvcBuilder
= MockMvcBuilders.standaloneSetup(employeeController);
RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder);
}
}
Generated test class:
import isc.co.ir.contractproducer.BaseTestClass;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import io.restassured.module.mockmvc.specification.MockMvcRequestSpecification;
import io.restassured.response.ResponseOptions;
import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat;
import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*;
import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;
import static io.restassured.module.mockmvc.RestAssuredMockMvc.*;
#SuppressWarnings("rawtypes")
public class ContractVerifierTest extends BaseTestClass {
#Test
public void validate_shouldReturnEmployee() throws Exception {
// given:
MockMvcRequestSpecification request = given()
.header("Content-Type", "application/json")
.body("{\"id\":25}");
// when:
ResponseOptions response = given().spec(request)
.post("/employee");
// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).matches("application/json.*");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field("['id']").isEqualTo(25);
assertThatJson(parsedJson).field("['fname']").isEqualTo("sara");
assertThatJson(parsedJson).field("['lname']").isEqualTo("ahmadi");
assertThatJson(parsedJson).field("['salary']").isEqualTo("25000.00");
assertThatJson(parsedJson).field("['gender']").isEqualTo("F");
}
}
Now when I build the project I get this error :
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.469 s <<< FAILURE! - in example.co.ir.contractproducer.ContractVerifierTest
[ERROR] validate_shouldReturnEmployee Time elapsed: 0.607 s <<< FAILURE!
org.opentest4j.AssertionFailedError:
Expecting:
<500>
to be equal to:
<200>
but was not.
When I build project using Junit4 everything is work fine but while using Junit5 I had this problem.
How can I fix this problem?
Please remove #SpringBootTest and use RestAssuredMockMvc.standaloneSetup or leave #SpringBootTest, inject WebApplicationContext and use RestAssuredMockMvc.webAppContextSetup(context)
Related
Need a help to write junit5 test case in springboot for a post api where it uses apache camel producer template to send message to kafka. Please find the controller class details for which junit test cases are required. Note-I don't have any service/repository layer for this.This is standalone controller which is responsible to publish message to kafka by using camel producer template.Thanks is advance.
Controller Class-->
`
`import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rms.inventory.savr.audit.model.AuditInfo;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MockKafkaProducerController {
#Autowired ProducerTemplate producerTemplate;
#Value("${audit.inbound.endpoint.kafka.uri:audit-json-topic}")
private String auditTopicKafka;
#Value("${camel.component.kafka.consumer.supply}")
private String supplyLineUpdateKafkaTopic;
#Value("${camel.component.kafka.consumer.demand}")
private String demandLineUpdateKafkaTopic;
#Value("${camel.component.kafka.consumer.supply-bucket}")
private String supplybucketTopicKafka;
#Value("${camel.component.kafka.consumer.demand-bucket}")
private String demandbucketTopicKafka;
#Value("${camel.component.kafka.consumer.availability}")
private String availabilityTopicKafka;
private Map<String, String> dataTypeTopicMap;
#PostConstruct
void init() {
dataTypeTopicMap =
Map.of(
"SUPPLY_LINE",
supplyLineUpdateKafkaTopic,
"SUPPLY_BUCKET",
supplybucketTopicKafka,
"DEMAND_LINE",
demandLineUpdateKafkaTopic,
"DEMAND_BUCKET",
demandbucketTopicKafka,
"AVAILABILITY",
availabilityTopicKafka);
}
#PostMapping("/api/mock/producer")
public ResponseEntity<Boolean> saveAuditInfo(#RequestBody AuditInfo auditInfo)
public ResponseEntity<Boolean> saveAuditInfo(
#RequestBody AuditInfo auditInfo, #RequestHeader("AUDIT_TYPE") String auditType)
throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
if (auditType == null || auditType.isEmpty()) {
auditType = "SUPPLY_LINE";
}
String topicName = dataTypeTopicMap.get(auditType);
// producerTemplate.
producerTemplate.sendBodyAndHeader(
auditTopicKafka, objectMapper.writeValueAsString(auditInfo), "messageFormat", "CANONICAL");
topicName, objectMapper.writeValueAsString(auditInfo), "messageFormat", "CANONICAL");
return ResponseEntity.ok(Boolean.TRUE);
}
#PostMapping("/api/inventory/audit/mock/producer")
public ResponseEntity<Boolean> publishInventoryAudit(#RequestBody String auditInfo)
public ResponseEntity<Boolean> publishInventoryAudit(
#RequestBody String auditInfo, #RequestHeader("AUDIT_TYPE") String auditType)
throws JsonProcessingException {
producerTemplate.sendBody(auditTopicKafka, auditInfo);
if (auditType == null || auditType.isEmpty()) {
auditType = "SUPPLY_LINE";
}
String topicName = dataTypeTopicMap.get(auditType);
producerTemplate.sendBody(topicName, auditInfo);
return ResponseEntity.ok(Boolean.TRUE);
}
}`
`
I tried to mock producer template but not able to fix.
I saw many of solutions provided here, on the forum, and also a guide for the problem (provided here), but none of them helped me...
I tried to keep my code cleare as much as I can, so I decided to create many of test classes including test items, for example:
#Getter
#Setter
public class SalesTaskTestItem {
public static SalesTask buildTestItem(){
List<ContactPerson> contactPersonTestItemList = new ArrayList<>();
contactPersonTestItemList.add(ContactPersonTestItem.buildTestItem());
List<SalesMan> supportingSalesTeamList = new ArrayList<>();
List<Product> discussedProductsTestList = new ArrayList<>();
discussedProductsTestList.add(ProductTestItem.buildTestItem());
List<SalesTaskProgress> progressTestList = new ArrayList<>();
progressTestList.add(SalesTaskProgressTestItem.buildTestItemNo1());
progressTestList.add(SalesTaskProgressTestItem.buildTestItemNo2());
progressTestList.add(SalesTaskProgressTestItem.buildTestItemNo3());
List<Offer> alreadySentOffersTestList = new ArrayList<>();
alreadySentOffersTestList.add(OfferTestItem.buildTestItem());
List<AssignedTaskDocument> assignedTaskDocumentsTestList = new ArrayList<>();
assignedTaskDocumentsTestList.add(AssignedTaskDocumentTestItem.buildTestItem());
List<InternalProcedureDocument> internalProceduresDocumentsTestList = new ArrayList<>();
internalProceduresDocumentsTestList.add(InternalProcedureDocumentTestItem.buildTestItem());
SalesTask testItem = new SalesTask();
testItem.setId(1L);
testItem.setVersion(1);
testItem.setTaskEstablishedDate(DateFormatter.fromStringToDate("10-12-2020T09:12:45"));
testItem.setLastProgressDate(DateFormatter.fromStringToDate("10-12-2020T09:30:56"));
testItem.setCompany(CompanyTestItem.buildTestItem());
testItem.setContactPersonsList(contactPersonTestItemList);
testItem.setMainSalesMan(SalesManTestItem.buildTestItemNo1());
testItem.setSupportingSalesTeam(supportingSalesTeamList);
testItem.setDiscussedProducts(discussedProductsTestList);
testItem.setProgressList(progressTestList);
testItem.setCurrentTaskValue(BigDecimal.valueOf(250000));
testItem.setChanceOfPositiveFinishingTask(0.45);
testItem.setEstimatedDateOfFinishingTask(DateFormatter.fromStringToDate("30-12-2020T13:00:00"));
testItem.setAlreadySentOffersList(alreadySentOffersTestList);
testItem.setAssignedTaskDocumentsList(assignedTaskDocumentsTestList);
testItem.setInternalProceduresDocumentsList(internalProceduresDocumentsTestList);
return testItem;
}
}
My test case is:
package com.jmdev.storycrm.controllers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.jmdev.storycrm.domain.salesTask.SalesTask;
import com.jmdev.storycrm.services.SalesTaskService;
import com.jmdev.storycrm.testDomainItems.salesTask.SalesTaskTestItem;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
#ExtendWith(SpringExtension.class)
#WebMvcTest
public class SalesTaskControllerTest {
#Autowired
MockMvc mockMvc;
#MockBean
private SalesTaskService salesTaskService;
#Test
public void createNewSalesTask(){
SalesTask newSalesTask = new SalesTask();
newSalesTask = SalesTaskTestItem.buildTestItem();
when(salesTaskService.save(any(SalesTask.class))).thenReturn(newSalesTask);
ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
try {
String newSalesTaskJSON = objectMapper.writeValueAsString(newSalesTask);
ResultActions resultActions = mockMvc.perform(
post("/salesTask")
.contentType(MediaType.APPLICATION_JSON)
.content(newSalesTaskJSON)
);
resultActions.andExpect(status().isCreated())
.andDo(print())
.andExpect(content().contentType("application/json"))
.andExpect(jsonPath("$.id").value(1L))
.andExpect(jsonPath("$.version").value(1))
.andExpect(jsonPath("$.taskEstablishedDate").value(SalesTaskTestItem.buildTestItem().getTaskEstablishedDate().toString()))
.andExpect(jsonPath("$.lastProgressDate").value(SalesTaskTestItem.buildTestItem().getLastProgressDate().toString()))
.andExpect(jsonPath("$.company").value(SalesTaskTestItem.buildTestItem().getCompany()))
.andExpect(jsonPath("$.contactPersonsList").value(SalesTaskTestItem.buildTestItem().getContactPersonsList()))
.andExpect(jsonPath("$.mainSalesMan").value(SalesTaskTestItem.buildTestItem().getMainSalesMan()))
.andExpect(jsonPath("$.supportingSalesTeam").value(SalesTaskTestItem.buildTestItem().getSupportingSalesTeam()))
.andExpect(jsonPath("$.discussedProducts").value(SalesTaskTestItem.buildTestItem().getDiscussedProducts()))
.andExpect(jsonPath("$.progressList").value(SalesTaskTestItem.buildTestItem().getProgressList()))
.andExpect(jsonPath("$.currentTaskValue").value(SalesTaskTestItem.buildTestItem().getCurrentTaskValue()))
.andExpect(jsonPath("$.chanceOfPositiveFinishingTask").value(SalesTaskTestItem.buildTestItem().getChanceOfPositiveFinishingTask()))
.andExpect(jsonPath("$.estimatedDateOfFinishingTask").value(SalesTaskTestItem.buildTestItem().getEstimatedDateOfFinishingTask()))
.andExpect(jsonPath("$.alreadySentOffersList").value(SalesTaskTestItem.buildTestItem().getAlreadySentOffersList()))
.andExpect(jsonPath("$.assignedTaskDocumentsList").value(SalesTaskTestItem.buildTestItem().getAssignedTaskDocumentsList()))
.andExpect(jsonPath("$.internalProceduresDocumentsList").value(SalesTaskTestItem.buildTestItem().getInternalProceduresDocumentsList()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
I see in stack trace my MockHttpServletResponse, where I can find "taskEstablishedDate":"2020-12-10T09:12:45.000+00:00". Also, If I copy whole body of this response and past it into https://jsonformatter.curiousconcept.com/, validation is passed with no problems.
MockHttpServletResponse:
Status = 201
Error message = null
Headers = [Content-Type:"application/json"]
Content type = application/json
Body = {"id":1,"version":1,"taskEstablishedDate":"2020-12-10T09:12:45.000+00:00","lastProgressDate":"2020-12-10T09:30:56.000+00:00", (...) }
Forwarded URL = null
Redirected URL = null
Cookies = []
But I get java.lang.AssertionError: No value at JSON path "$.taskEstablishedDate".
I really don't know what is wrong. Could anybody help?
EDIT: I implemented SSK suggestions and dates and time are passing now. For test next of JSON values, provided as my app's objects, I implemented GSON into override toString() method:
package com.jmdev.storycrm.domain.company;
import com.jmdev.storycrm.utils.JSONFormatter;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
#Getter
#Setter
public class Company {
#Id
private Long id;
private String name;
private Long nipNumber;
private Address address;
#Override
public String toString() {
return JSONFormatter.useGSON(this);
}
}
Used toString() formatter:
package com.jmdev.storycrm.utils;
public class JSONFormatter {
public static String useGSON(Object object){
return new com.google.gson.Gson().toJson(object);
}
}
But I'm getting java.lang.AssertionError for both values which are completely the same...
java.lang.AssertionError: JSON path "$.company" (...)
Expected :{"id":1,"name":"TestCompanyName","nipNumber":345353534354335,"address":{"id":1,"voivodeship":"Region name","postalCode":"99-000","city":"My City name","street":"Main Street name","fullBiuldingNumber":"100","flatNumber":1}}
Actual :{"id":1,"name":"TestCompanyName","nipNumber":345353534354335,"address":{"id":1,"voivodeship":"Region name","postalCode":"99-000","city":"My City name","street":"Main Street name","fullBiuldingNumber":"100","flatNumber":1}}
You need to register your JavaTimeModule with ObjectMapper.
You can register JavaTimeModule as shown below.
ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
Then use the same objectMapper to create the json string
String newSalesTaskJSON = objectMapper.writeValueAsString(newSalesTask);
JavaTimeModule is from com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
Also, you need to add .toString() to your date values in .andExpect() as shown below
.andExpect(jsonPath("$.taskEstablishedDate").value(SalesTaskTestItem.buildTestItem().getTaskEstablishedDate().toString()))
.andExpect(jsonPath("$.lastProgressDate").value(SalesTaskTestItem.buildTestItem().getLastProgressDate().toString()))
.andExpect(jsonPath("$.estimatedDateOfFinishingTask").value(SalesTaskTestItem.buildTestItem().getEstimatedDateOfFinishingTask().toString()))
I have no idea why I am getting this error here. Any thoughts?
Here is my repository code
package movieweb.movies.repository;
import movieweb.movies.models.Movies;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface MoviesRepository extends CrudRepository<Movies, Integer> {
}
Here is my Controller code.
package movieweb.movies.controllers;
import movieweb.movies.models.Movies;
import movieweb.movies.models.UserMovies;
import movieweb.movies.repository.MoviesRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.server.ResponseStatusException;
#RestController
public class MoviesController {
#Autowired
private MoviesRepository moviesRepository;
#Autowired
private RestTemplate restTemplate;
#CrossOrigin
#GetMapping(path = "/movies")
public List<Movies> movies(){
List<Movies> allMovies = (List<Movies>) moviesRepository.findAll();
if (!allMovies.isEmpty()){
return allMovies;
} else {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Movies not found"
);
}
}
// #CrossOrigin
// #RequestMapping(path = "movies/user/{id}")
// public List<Movies> movie(#PathVariable("id") int id){
// return this.movies().stream().map(movie -> {
// Users[] user = restTemplate.getForObject("http://127.0.0.1:8082/users/" + id, Users[].class);
// return new Movies(movie.getMovieId(), movie.getMovieName(), "Description");
// })
// .collect(Collectors.toList());
// }
#CrossOrigin
#GetMapping(path="/movie/{id}")
public Movies getMovie(#PathVariable Integer id){
return moviesRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(
HttpStatus.NOT_FOUND, "Movie not found"
) );
}
#CrossOrigin
#DeleteMapping("/movie/delete/{id}")
void deleteMovie(#PathVariable Integer id) {
moviesRepository.deleteById(id);
}
#CrossOrigin
#PutMapping("/movie/update/{id}")
Movies updateMovie(#RequestBody Movies updateMovie, #PathVariable Integer id) {
return moviesRepository.findById(id)
.map(Movies -> {
Movies.setMovieName(updateMovie.getMovieName());
Movies.setMovieDescription(updateMovie.getMovieDescription());
return moviesRepository.save(Movies);
})
.orElseGet(() -> {
updateMovie.setMovieId(id);
return moviesRepository.save(updateMovie);
});
}
#CrossOrigin
#PostMapping(path="/newMovie")
public Movies addNewMovie (#RequestBody Movies data) {
return moviesRepository.save(data);
}
}
and here is my test (updated)
package movieweb.movies;
import movieweb.movies.controllers.MoviesController;
import movieweb.movies.models.Movies;
import movieweb.movies.repository.MoviesRepository;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
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.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.testng.annotations.BeforeMethod;
import java.util.ArrayList;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#SpringBootTest
#AutoConfigureMockMvc
class MovieApplicationTests {
#Autowired
MockMvc mockMvc;
#MockBean
MoviesRepository moviesRepository;
#MockBean
MoviesController moviesController;
#Autowired
private WebApplicationContext webApplicationContext;
#BeforeMethod
public void init() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
void getAllMovies() throws Exception{
ArrayList<Movies> moviesList = new ArrayList<Movies>();
moviesList.add(new Movies(1, "Star Wars", "A New Hope"));
moviesList.add(new Movies(2, "Star Wars", "Empire Strikes Back"));
when(moviesRepository.findAll()).thenReturn(moviesList);
mockMvc.perform(get("/movies"))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].movieName", is("Star Wars")))
.andExpect(jsonPath("$[0].movieDescription", is("A New Hope")))
.andExpect(jsonPath("$[1].movieName", is("Star Wars")))
.andExpect(jsonPath("$[1].movieDescription", is("Empire Strikes Back")));
Mockito.verify(moviesRepository, times(1)).findAll();
}
}
The error I am getting in my stacktrace is the following....
java.lang.AssertionError: JSON path "$"
Expected: a collection with size <2>
but: collection size was <0>
Why is it zero and not the 2 items I created in my movieList ArrayList?
I'm guessing its something to do with my configuration?
You are mocking your controller:
#MockBean
MoviesController moviesController;
Thus, you replaced the real controller under test with this mock.
To have real controller you need to get rid of these lines.
To further improve, learn about #WebMvcTest to test only the web slice of your app.
Im running a JUnit test with Mockito in my Spring Boot application. I am mocking the repository which the controller is supposed to call. I am getting a HttpMessageNotReadableException when running the POST test with a response code of 400 (The GET works fine).
package coffee;
import static org.junit.Assert.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.*;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import coffee.controller.AboutController;
import coffee.data.AboutRepository;
#RunWith(SpringRunner.class)
#WebMvcTest(value = AboutController.class, secure = false)
public class AboutControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private AboutRepository aboutRepository;
List<About> res;
#Before
public void setUp() {
res = new ArrayList<About>();
About about = new About();
about.setName("Test");
res.add(about);
}
#Test
public void postAbouts() throws Exception{
About about = res.get(0);
Mockito.when(aboutRepository.save(about))
.thenReturn(about);
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/abouts")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content("{'id':null,'position':null,'name':'Test','description':null,'image':null}");
MvcResult result = mockMvc.perform(requestBuilder)
.andExpect(status().isOk())
.andReturn();
JSONAssert.assertEquals("{'id':null,'position':null,'name':'Test','description':null,'image':null}",
result.getResponse().getContentAsString(),
false);
}
}
MockHttpServletRequest:
HTTP Method = POST
Request URI = /abouts
Parameters = {}
Headers = {Content-Type=[application/json], Accept=[application/json]}
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = coffee.controller.AboutController
Method = public coffee.About coffee.controller.AboutController.postAbout(coffee.About)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.http.converter.HttpMessageNotReadableException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 400
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
2019-05-21 14:47:56.035 INFO 1977 --- [ Thread-4] o.s.w.c.s.GenericWebApplicationContext : Closing org.springframework.web.context.support.GenericWebApplicationContext#7fd50002: startup date [Tue May 21 14:47:54 PDT 2019]; root of context hierarchy
Here is the controller that is being tested
package coffee.controller;
import coffee.*;
import coffee.data.AboutRepository;
import java.util.Optional;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping(path="abouts",
produces="application/json",
consumes="application/json")
#CrossOrigin(origins="*")
public class AboutController {
private AboutRepository aboutRepo;
public AboutController(AboutRepository aboutRepo) {
this.aboutRepo = aboutRepo;
}
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public About postAbout(#RequestBody About about) {
return aboutRepo.save(about);
}
}
it looks like the About json is invalid. Can you try with json with double quotes on the content method ?
{ "id":null, "position":null, "name":"Test", "description":null, "image":null }
I have a RestController that I'm attempting to test via Spring MVC Test. It has the following ModelAttribute in it:
#ModelAttribute("authUser")
public User authUser(#AuthenticationPrincipal SpringAuthUser springAuthUser) throws Exception {
User user = ConstantsHome.userprofileMgr.getUserByUserId(springAuthUser.getUsername(), true, true);
user.updateRights(null);
request.getSession().setAttribute(ConstantsHome.USEROBJECT_KEY, user);
return user;
}
When I run a test against this RestController, I'm getting a NullPointerException inside this authUser method.
Is there a way to mock this method such that the mocked method gets used instead of this one for testing? I've read other posts on this and thought I could just pass an "authUser" param in my test but that's not working. Ultimately trying to make this "authUser" not throw an NPE...here is my test...
#Test
public void testGetAllUsers() throws Exception {
String userJson = AvadaObjectMapper.getMapper().writeValueAsString(new User());
System.out.println("userJson=" + userJson);
MvcResult result = this.mockMvc.perform(get("/").param("authUser", userJson).accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json"))
.andDo(print())
.andReturn();
String content = result.getResponse().getContentAsString();
assertTrue(content.contains("Hello"));
}
I was able to get my authUser to work via the test configuration class below. Pay attention to the .defaultRequest... line in particular as that is where the auth user gets established. I use the class below as the #ContextConfiguration class on all of my tests.
import com.avada.rest.api.users.UserService;
import com.avada.rest.api.users.TestUserService;
import com.avada.rest.security.SpringAuthUser;
import java.util.HashSet;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
#Configuration
#ComponentScan(excludeFilters={
#ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=UserService.class)
})
public class TestSpringRestConfig {
public static final SpringAuthUser AUTH_USER =
new SpringAuthUser("test", "test",
new HashSet<GrantedAuthority>() {{
add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}}
);
#Bean
public UserService userService() {
return new TestUserService();
}
#Bean
public MockMvc mockMvc(WebApplicationContext wac) {
return MockMvcBuilders
.webAppContextSetup(wac)
.defaultRequest(MockMvcRequestBuilders.get("/").with(SecurityMockMvcRequestPostProcessors.user(AUTH_USER)))
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
}