I'm trying to test my rest controller. No issues with GETs, but when I try to test a POST method I'm unable to attach the body.
private static final MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
private ObjectMapper jsonMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
#Test
public void test1() throws Exception {
//...Create DTO
//...Create same pojo but as entity
when(serviceMock.addEntity(e)).thenReturn(e);
mvc.perform(post("/uri")
.contentType(contentType)
.content(jsonMapper.writeValueAsString(dto))
)
.andDo(print())
.andExpect(status().isCreated())
.andExpect(content().contentType(contentType)); //fails because there is no content returned
}
This is the request output:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /uri
Parameters = {}
Headers = {Content-Type=[application/json;charset=UTF-8]}
There is no body. Why? I have printed jsonMapper.writeValueAsString(dto) and is not null.
edit:
Adding controller code:
#RestController
#RequestMapping("/companies")
public class CompanyController {
#Autowired
private CompanyService service;
#Autowired
private CompanyMapper mapper;
#RequestMapping(method=RequestMethod.GET)
public List<CompanyDTO> getCompanies() {
List<Company> result = service.getCompanies();
return mapper.toDtoL(result);
}
#RequestMapping(method=RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public CompanyDTO createCompany(#RequestBody #Valid CompanyDTO input) {
Company inputE = mapper.toEntity(input);
Company result = service.addCompany(inputE);
return mapper.toDto(result);
}
Solved.
The mock call should use any instead of a concrete object: when(serviceMock.addCompany(any(Company.class))).thenReturn(e);
I needed to override the equals method of the entity class to pass this statement: verify(serviceMock, times(1)).addCompany(e);
Related
I have 3 classes involved in my problem: MyService, MyServiceTest, MyConfig and a yaml file application.yml. MyRequest and MyResponse are my custom classes which denotes the incoming request to service class from controller and outgoing response from service class to controller respectively.
I am getting below error:
SAAJ007: Bad Endpoint type
application.yml
backside:
url: https://mybackend.com/my/operation
ssl:
store: D:\\mydata\\myconfiguration\\mykey.jks
token: password
MyService.java
#Service
public class MyService{
#Value("${backside.url}")
private String backsideUrl;
private MyFormatter formatter; // has methods which formats request and response
private SOAPConnectionFactory soapFactory;
#Autowired
public MyService(MyFormatter formatter, SOAPConnectionFactory soapFactory){
this.formatter = formatter;
this.soapConnectionFactory = soapConnectionFactory;
}
public MyResponse createSomething(MyRequest request){
MyResponse response;
try{
SOAPConnection connection = soapConnectionFactory.createConnection();
SOAPMessage soapResponse = connection.call(formatter.formatRequest(request), backsideUrl); // formatRequest(MyRequest request) returns object of SOAPMessage
response = formatter.formatResponse(soapResponse); // formatResponse(SOAPMessage soapMsg) returns object of MyResponse
connection.close();
}
catch(SOAPException ex){
logger.error("SOAP Connection Error:{}", ex.toString());
throw MyCustomException("MyErrorMsg", HttpStatus.INTERNAL_SERVER_ERROR);
}
catch(Exception ex){
logger.error("Unknown Error:{}", ex.toString());
throw MyCustomException("UnknownErrorMsg", HttpStatus.INTERNAL_SERVER_ERROR);
}
return response;
}
}
MyConfiguration.java
#Configuration
public class MyConfiguration{
#Value("${ssl.store}")
private String keyPath;
#Value("${ssl.token}")
private String keyPassword;
#Bean
public SOAPConnectionFactory soapConnectionFactory() throws SOAPException{
return SOAPConnectionFactory.newInstance();
}
#Bean
public void addSSLCertificate() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithException, UnrecoverableKeyException, KeyManagementException{
// lines of code which uses #Value annotated keyPath and keyPassword fields
}
}
MyServiceTest.java
#ExtendWith(SpringExtension.class)
public class MyServiceTest{
#Mock
private SOAPConnectionFactory soapConnectionFactory;
#Mock
private SOAPConnection soapConnection;
#Mock
private MyFormatter formatter;
#InjectMocks
private MyService service;
private MyRequest request;
private MyResponse expectedResponse;
private SOAPMessage soapRequest;
private SOAPMessage soapResponse;
#BeforeEach
void initializeObjects() throws SOAPException{
// Lines of code creating an object of MyRequest and setting its field values : request
// Lines of code creating an object of MyResponse and setting its field values : expectedResponse
// Lines of code creating an object of SOAPMessage: soapRequest
// Lines of code creating an object of SOAPMessage: soapResponse
}
#Test
public void myTestCase(){
Mockito.when(soapConnectionFactory.createConnection()).thenReturn(soapConnection);
Mockito.when(formatter.formatRequest(any(MyRequest.class))).thenReturn(soapRequest);
Mockito.when(soapConnection.call(any(SOAPMessage.class), any(String.class))).thenReturn(soapResponse);
Mockito.when(formatter.formatResponse(any(SOAPMessage.class))).thenReturn(expectedResponse);
MyResponse actualResponse = service.createSomething(request);
Assertions.assertEquals(expectedResponse.toString(), actualResponse.toString()); // overridden toString() method exists in the definition of MyResponse class
}
}
Since the value of String object i.e. backsideUrl is not mocked and hence it will not get assigned, then at the time of connection.call(formatter.formatRequest(request), backsideUrl) method execution, the value of backsideUrl will be null. So the mock is not going to working properly because we are using any(String.class).
Instead of this:
Mockito.when(soapConnection.call(any(SOAPMessage.class), any(String.class))).thenReturn(soapResponse);
Use this:
Mockito.when(soapConnection.call(any(SOAPMessage.class), any())).thenReturn(soapResponse);
I am trying to learn Junit and I ended up in a situation where my testcase returns 200 status code but returns null response Body. Its just a simple save operation using JPA repo and I have tried many online solutions but none worked for me.
Testclass :
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
class CarManufacturingSystemApplicationTests {
#Autowired
private MockMvc mockMvc;
#MockBean
private GroupController groupController;
ObjectMapper om = new ObjectMapper();
#Test
public void createGroupTest() throws Exception {
GroupCreateRequest createRequest = new GroupCreateRequest();
createRequest.setActiveFlag(true);
createRequest.setGroupName("test");
createRequest.setPlantCode(1L);
String expectedjson = "{\r\n" + "\"message\": \"Group created successfully\"\r\n" + "}";
MvcResult result = mockMvc.perform(post("/group/createGroup")
.contentType(MediaType.APPLICATION_JSON_VALUE).accept(MediaType.APPLICATION_JSON_VALUE).content(new Gson().toJson(createRequest)))
.andExpect(status().isOk())
.andReturn();
String actualJson = result.getResponse().getContentAsString();
Assert.assertEquals(expectedjson, actualJson);
}
Controller:
#RestController
#RequestMapping(value = "/group")
public class GroupController {
#Autowired
private GroupService groupService;
#PostMapping("/createGroup")
public ResponseEntity<Response> createGroup(#RequestBody GroupCreateRequest groupCreateRequest) {
Response response = groupService.createGroup(groupCreateRequest);
return new ResponseEntity<> (response, HttpStatus.OK);
}
}
Error:
org.junit.ComparisonFailure: expected:<[{
"message": "Group created successfully"
}]> but was:<[]>
at org.junit.Assert.assertEquals(Assert.java:115)
at org.junit.Assert.assertEquals(Assert.java:144)
at com.nissan.car.manufacturing.system.CarManufacturingSystemApplicationTests.createGroupTest(CarManufacturingSystemApplicationTests.java:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
Service implementation
public Response createGroup(GroupCreateRequest groupCreateRequest) {
Group group = new Group();
Response response = new Response();
try {
addGroupDetails(groupCreateRequest, group);
groupRepository.save(group);
Note that your are testing GroupController, not GroupService, so you should mock the GroupService. Please replace
#MockBean
private GroupController groupController;
to
#MockBean
private GroupService groupService;
And then using simple stubbing directives when(something).thenReturn(somethingElse) to make your groupService return the response you specified.
#Test
public void createGroupTest() throws Exception {
// ...
Response response = new Response();
response.setMessage("Group created successfully");
when(groupService.createGroup(any())).thenReturn(response);
// ...
Assert.assertEquals(expectedjson, actualJson);
}
I have following the controller which accepts post request and returns Response Entity with body
#RestController
public class UserController {
#Autowired
private UserService UserService;
#RequestMapping(value = "/all", method = POST,consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<ResponseUser>> navigationTree(#RequestBody(required=false) UserDataRequest request) {
return UserService.sendEntries(request);
}
}
This is the test I wrote I for it:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class UserControllerTest {
private MockMvc mockMvc;
#MockBean
private UserService UserServiceMock;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setUp() {
this.mockMvc = webAppContextSetup(webApplicationContext).build();
}
#Test
public void returnTopLevel() throws Exception {
String expectedJson = "[{\"id\":\"11\",\"name\":\"11\"},{\"id\":\"22\",\"name\":\"22\"}]";
MvcResult result = this.mockMvc.perform(post("/all")
.contentType(MediaType.APPLICATION_JSON)
.content("")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andReturn();
String actualJson = result.getResponse().getContentAsString();
// System.out.println(result);
//assertThat(Objects.equals(expectedJson, actualJson)).isTrue();
verify(UserServiceMock,times(1)).sendEntries(null);
}
}
I want to compare string received in response body to expected string.
I tried the string comparison but it's not working
Errors :
assertThat(Objects.equals(expectedJson, actualJson)).isTrue();
and actualjson is empty.
What are the other ways?
You need to mock the UserService to return something before executing this.mockMvc.perform. Something like this:
when(UserServiceMock.sendEntries(null)).thenReturn(expectedResponceEntity);
So just construct the expected response then mock UserService to return it.
This are the annotated methods in the controller:
#RequestMapping(method = RequestMethod.GET)
public String getClient(#PathVariable("contractUuid") UUID contractUuid, Model model) {
ClientDto clientDto = new ClientDto();
clientDto.setContractUuid(contractUuid);
model.addAttribute("client", clientDto);
return "addClient";
}
#ModelAttribute("contract")
public ContractDto getContract(#PathVariable("contractUuid") UUID contractUuid) throws ContractNotFoundException {
return contractService.fromEntity(contractService.findByUuid(contractUuid));
}
The test method that I am trying is shown below, but it fails for attribute contract. The attribute client is added to the Model in a #RequestMapping method.
private MockMvc mockMvc;
#Autowired
private ContractService contractServiceMock;
#Autowired
private ClientService clientServiceMock;
#Autowired
protected WebApplicationContext wac;
#Before
public void setup() {
Mockito.reset(contractServiceMock);
Mockito.reset(clientServiceMock);
this.mockMvc = webAppContextSetup(this.wac).build();
}
#Test
public void test() throws Exception {
UUID uuid = UUID.randomUUID();
Contract contract = new Contract(uuid);
when(contractServiceMock.findByUuid(uuid)).thenReturn(contract);
mockMvc.perform(get("/addClient/{contractUuid}", uuid))
.andExpect(status().isOk())
.andExpect(view().name("addClient"))
.andExpect(forwardedUrl("/WEB-INF/pages/addClient.jsp"))
.andExpect(model().attributeExists("client"))
.andExpect(model().attributeExists("contract"));
}
The contract attribute shows in the jsp page when I run the application, since I use some of its attributes, but since it fails in the test method is there another way to test it ?
It fails with the message:
java.lang.AssertionError: Model attribute 'contract' does not exist
Spring is 4.0.1.RELEASE
It seems it was my fault.
Even though the #ModelAttribute method returns an instance of ContractDto I only mocked one method used from the service:
when(contractServiceMock.findByUuid(uuid)).thenReturn(contract);
and so findByUuid returned something, but contractService.fromEntity was left untouched so I had to also mock it:
UUID uuid = UUID.randomUUID();
Contract contract = new Contract(uuid);
ContractDto contractDto = new ContractDto(uuid);
when(contractServiceMock.findByUuid(uuid)).thenReturn(contract);
when(contractServiceMock.fromEntity(contract)).thenReturn(contractDto);
I have a very simple RESTful Controller that consumes and produces JSON. I need to test this controller offline i.e. no server running, no database running. And I am going nuts for not being able to find a solution. My intial test cases will include:
Test REST URIs i.e. GET, POST, PUT, DELETE - I must be able to Assert data returned against data sent.
Assert will test JSON data
I have the following URIs:
/pcusers - Returns all users
/pcusers/{id} - Return a specific user
/pcusers/create/{pcuser} - Add user to db
/pcusers/update/{pcuser} - Update user
/pcusers/delete/{id} - Delete User
NOTE: This is NOT a typical MVC application. I DO NOT have Views. I have a pure REST controller that spits out JSON and consumes data in JSON format.
If someone could guide me in the right direction would be really appreciated.
Just to be clear how my code looks like:
#Controller
#RequestMapping("/pcusers")
public class PcUserController {
protected static Logger logger = Logger.getLogger(PcUserController.class);
#Resource(name = "pcUserService")
private PcUserService pcUserService;
#RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public List<PcUser> readAll() {
logger.debug("Delegating to service to return all PcUsers");
return pcUserService.readAll();
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET, consumes = "application/json", produces = "application/json")
#ResponseBody
public PcUser read(#PathVariable String id) {
logger.debug("Delegating to service to return PcUser " + id);
return pcUserService.read(id);
}
#RequestMapping(value = "/create/{pcUser}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
#ResponseBody
public boolean create(#PathVariable PcUser pcUser) {
logger.debug("Delegating to service to create new PcUser");
return pcUserService.create(pcUser);
}
#RequestMapping(value = "/update/{pcUser}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
#ResponseBody
public boolean update(#PathVariable PcUser pcUser) {
logger.debug("Delegating to service to update existing PcUser");
return pcUserService.update(pcUser);
}
#RequestMapping(value = "/delete/{id}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
#ResponseBody
public boolean delete(#PathVariable String id) {
logger.debug("Delegating to service to delete existing PcUser");
return pcUserService.delete(id);
}
}
UPDATE (2/5/2012):
After some research, I came across a Spring framework called spring-test-mvc. It looks very promising and I have managed to get a good start on this. But now I have a new problem. When I submit a GET request to "/pcusers/{id}", the control is passed to read method which is responsible for handling that mapping. Inside that method I have a pcUserService that does a read. Now, the problem is when I run this test, the pcUserService instance inside real controller is NULL; and therefore it ends up crashing as read cannot be called on a NULL object.
Here's PcUserControllerTest code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:/applicationContextTest.xml")
public class PcUserControllerTest {
#Autowired
PcUserService pcUserService;
#Autowired
PcUserController pcUserController;
PcUser pcUser;
#Before
public void setUp() throws Exception {
pcUser = new PcUser("John", "Li", "Weasley", "john", "john", new DateTime());
pcUserService.create(pcUser);
}
public void tearDown() throws Exception {
pcUserService.delete(pcUser.getId());
}
#Test
public void shouldGetPcUser() throws Exception {
standaloneSetup(pcUserController)
.build()
.perform(get("/pcusers/" + pcUser.getId()).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
Here is one suggestion that should give you some ideas. I assume that you are familiar with the SpringJUnit4ClassRunner and the #ContextConfiguration. Start by creating an test application context that contains PcUserController and a mocked PcUserService. In the example PcUserControllerTest class below, Jackson is used to convert JSON messages and Mockito is used for mocking.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(/* Insert test application context here */)
public class PcUserControllerTest {
MockHttpServletRequest requestMock;
MockHttpServletResponse responseMock;
AnnotationMethodHandlerAdapter handlerAdapter;
ObjectMapper mapper;
PcUser pcUser;
#Autowired
PcUserController pcUserController;
#Autowired
PcUserService pcUserServiceMock;
#Before
public void setUp() {
requestMock = new MockHttpServletRequest();
requestMock.setContentType(MediaType.APPLICATION_JSON_VALUE);
requestMock.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
responseMock = new MockHttpServletResponse();
handlerAdapter = new AnnotationMethodHandlerAdapter();
HttpMessageConverter[] messageConverters = {new MappingJacksonHttpMessageConverter()};
handlerAdapter.setMessageConverters(messageConverters);
mapper = new ObjectMapper();
pcUser = new PcUser(...);
reset(pcUserServiceMock);
}
}
Now, we have all the code needed to create the tests:
#Test
public void shouldGetUser() throws Exception {
requestMock.setMethod("GET");
requestMock.setRequestURI("/pcusers/1");
when(pcUserServiceMock.read(1)).thenReturn(pcUser);
handlerAdapter.handle(requestMock, responseMock, pcUserController);
assertThat(responseMock.getStatus(), is(HttpStatus.SC_OK));
PcUser actualPcUser = mapper.readValue(responseMock.getContentAsString(), PcUser.class);
assertThat(actualPcUser, is(pcUser));
}
#Test
public void shouldCreateUser() throws Exception {
requestMock.setMethod("POST");
requestMock.setRequestURI("/pcusers/create/1");
String jsonPcUser = mapper.writeValueAsString(pcUser);
requestMock.setContent(jsonPcUser.getBytes());
handlerAdapter.handle(requestMock, responseMock, pcUserController);
verify(pcUserServiceMock).create(pcUser);
}