I am trying to test my controller using MockMvc. While performing this mockMvc.perform(requestBuilder).andReturn(); It doesn't hit my API. So I am getting this response.
org.junit.ComparisonFailure: The Mock Response object should be same
Expected :dGVzdDEyMw==
Actual :
This is my controller class
public class AddLibClientRestController
{
#Autowired
private AddAPIService addAPIService;
#PostMapping(value = "/v1/add")
public String encrypt (#RequestParam final String plainText) throws GeneralSecurityException
{
return addAPIService.add(plainText);
}
}
This is my test class
public class AddLibClientRestControllerTest
{
/** The instance of EncryptionAPIService. */
#MockBean
private AddAPIService mockAddAPIService;
#Autowired
private MockMvc mockMvc;
#Test
public void testEncryptWithMockObjectReturned () throws Exception
{
final MockHttpServletRequestBuilder requestBuilder =
post("/v1/add")
.param("plainText", "test123");
when(mockAddAPIService.add(anyString())).thenReturn("dGVzdDEyMw==");
final MvcResult result = mockMvc.perform(requestBuilder).andReturn();
assertEquals("The Mock Response object should be same", "dGVzdDEyMw==",
result.getResponse().getContentAsString());
}
}
Please suggest something, what i am doing wrong here in this. Thanks
Related
So I am working with a working UI, and using a DB2 database. I am trying to run unit testing on the controller/service/dao layers and I am using mockito and junit to test. Here are the pieces of each layer:
Measures.java
#Controller
#RequestMapping(value = "/measures"})
public class Measures {
#Resource
private CheckUpService checkUpService;
public void setCheckUpService(CheckUpService checkUp) {
this.checkUpService = checkUpService;
}
#RequestMapping(value = "/eligibility/{userId}/{effDate}/{stageInd}", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody List<Model> findEligibility(#PathVariable int userId, #PathVariable String effDate, #PathVariable String stageInd) throws Exception
{
List<Model> result = new ArrayList<Model>();
if (stageInd.equals("stage"))
{
result = checkUpService.findEligibilityStage(userId, effDate);
}
if (stageInd.equals("prod"))
{
result = checkUpService.findEligibility(userId, effDate);
}
return result;
}
...
}
CheckUpService.java
public class CheckUpService {
#Resource
EligibilityDao eligDao;
public List<Model> findEligibility(int userId, String effDate) throws Exception
{
return eligDao.findEligibility(userId, effDate, db_table);
}
}
EligibilityDao.class
public class EligibilityDao {
public List<Model> findEligibility(int userId, String effDate, String table) throws Exception
{
// uses some long sql statement to get some information db2 database and
// jdbctemplate helps return that into a list.
}
}
Here is the controller test that I am trying to do, I've spent about 10 hours on this and I really can't figure out why it's giving me a 406 error instead of 200.
ControllerTest.java
#EnableWebMvc
#WebAppConfiguration
public class ControllerTest {
#Autowired
private Measures measures;
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
private List<Model> findEligibility() {
List<Model> list = new ArrayList<>();
Model test_model = new Model();
test_model.setUserId(99);
test_model.setCreateID("testUser");
test_model.setEffDate("2020-07-30");
list.add(test_model);
return list;
}
#Before
public void setup() throws Exception {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void test_find() throws Exception {
CheckUpService checkUpService = mock(CheckUpService.class);
when(checkUpService.findEligibility(99, "2020-07-30")).thenReturn(findEligibility());
measures.setCheckUpService(checkUpService);
String URI = "/measures/eligibility/99/2020-07-30/prod";
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(URI).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
MvcResult handle = mockMvc.perform(requestBuilder).andReturn();
// MvcResult handle = mockMvc.perform(requestBuilder).andExpect(status().isOk()).andReturn();
MvcResult result = mockMvc.perform(asyncDispatch(handle)).andExpect(status().isOk()).andReturn();
// assertThat(result.getResponse().getContentAsString()).isEqualTo(findEligibility());
}
}
The MvcResult result is what is throwing the "StatusExpected <200> but was <406>" error in junit and i'm going mad on why it is. Another issue is that, if you can see, I commented out the handle with the .andExpect(status().isOk()) and that one was also throwing the same issue. Is it something i'm setting up wrong with the test or something?
I could not reproduce your issue. However, I got this working.
So, no big changes to the Controller, but I removed the field injection in favor of constructor injection.
#Controller
#RequestMapping(value = "/measures")
public class Measures {
private final CheckUpService checkUpService;
public Measures(CheckUpService checkUpService) {
this.checkUpService = checkUpService;
}
#RequestMapping(value = "/eligibility/{userId}/{effDate}/{stageInd}", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody List<Model> findEligibility(#PathVariable int userId, #PathVariable String effDate, #PathVariable String stageInd) throws Exception {
List<Model> result = new ArrayList<>();
if (stageInd.equals("stage")) {
result = checkUpService.findEligibility(userId, effDate);
}
if (stageInd.equals("prod")) {
result = checkUpService.findEligibility(userId, effDate);
}
return result;
}
}
The same for the service class.
#Service
public class CheckUpService {
private final EligibilityDao dao;
public CheckUpService(EligibilityDao dao) {
this.dao = dao;
}
public List<Model> findEligibility(int userId, String effDate) throws Exception {
return dao.findEligibility(userId, effDate, "demo value");
}
}
and here's the test. Instead of initializing the MockMvc and injecting the web context, I inject MockMvc. Also, using #MockBean, you can inject mocks. So, I removed the mock creation from the test method to the initialization part.
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class MeasuresTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private CheckUpService service;
#Test
public void test_find() throws Exception {
Model model = new Model(99, "2020-08-02", "2020-07-30");
when(service.findEligibility(99, "2020-07-30"))
.thenReturn(Collections.singletonList(model));
String URI = "/measures/eligibility/99/2020-07-30/prod";
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post(URI)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON);
final MvcResult mvcResult = mockMvc.perform(requestBuilder)
.andExpect(status().isOk()).andReturn();
final String json = mvcResult.getResponse().getContentAsString();
final List<Model> models = new ObjectMapper().readValue(json, new TypeReference<>() {
});
Assert.assertEquals(1, models.size());
Assert.assertEquals(model, models.get(0));
}
}
In the post, I could not find any reason why you used asyncDispatch, so I just did not use it.
If I try to test the post() endpoint, I see:
java.lang.AssertionError: No value at JSON path "$.firstName"
Caused by: java.lang.IllegalArgumentException: json can not be null or empty
But with the test for the get() all work fine.
And in the postTest() the result for status is correct.
Where is my mistaker?
Is it correct way to test the rest controller in this style?
#RunWith(MockitoJUnitRunner.Silent.class)
public class Temp {
private final Employee successfullyRegisteredEmployee = new Employee(2L, "Iven");
private final Employee employeeGetById = new Employee(2L, "Iven");
#Mock
private EmployeeServiceImpl serviceMock;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(new EmployeeControllerImpl( serviceMock))
.build();
}
#Test
public void getTest() throws Exception {
when(serviceMock.getEmployee(2L)).thenReturn(employeeGetById);
mockMvc.perform(get("/employee/get/2"))
.andExpect(status().is(200))
.andExpect(content().json(("{'firstName':'Iven'}")));
verify(serviceMock).getEmployee(2L);
}
#Test
public void postTest() throws Exception {
String json = "{\n" +
" \"firstName\": \"Iven\"\n"
"}";
when(serviceMock.register(employeeForRegister)).thenReturn(successfullyRegisteredEmployee);
mockMvc.perform( MockMvcRequestBuilders
.post("/employee/register")
.content(json)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is(201))
.andExpect(jsonPath("$.firstName", Matchers.is("Iven")));
}
}
#RestController
#RequestMapping("/employee")
public class EmployeeControllerImpl implements EmployeeController {
private final EmployeeService service;
public EmployeeControllerImpl(EmployeeService service) {
this.service = service;
}
#PostMapping(path = "/register",
consumes = "application/json",
produces = "application/json"
)
public ResponseEntity<Employee> registerEmployee(#Valid #RequestBody Employee employee) {
Employee registeredEmployee = service.register(employee);
return ResponseEntity.status(201).body(registeredEmployee);
}
}
Seems like problem could be with when(serviceMock.register(employeeForRegister)).thenReturn(successfullyRegisteredEmployee);.
Did you try to have breakpoint on return ResponseEntity.status(201).body(registeredEmployee); to check if registeredEmployee is actually filled?
If it's empty then try replacing mock with when(serviceMock.register(any())).thenReturn(successfullyRegisteredEmployee); and if it works that means either equals() method is not overridden for Employee or comparison just fails.
I'm developing a REST API with Spring Boot.
I have a controller to create a new user, that responds with 201 (CREATED) when the user is created. The response has no body content.
Using Postman, or any browser, I got a 201 response.
But when I try with unit test (Mockito), the response is 200.
Here is my code:
Controller:
public CompletableFuture<ResponseEntity<Void>> registerNewUser(
#RequestBody #Valid RegisterUserDto newUser
) throws ExecutionException, InterruptedException {
// user service return a completable future void
return userService.registerNewUser(newUser).thenApply(u -> new ResponseEntity<>(u, HttpStatus.CREATED));
}
The user service returns a completable future void when the register process is completed.
#Async
CompletableFuture<Void> registerNewUser(NewUserDto newUserDto) throws ExecutionException, InterruptedException;
Then, in my unit test, I have the following code:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class UsersControllerTest {
#Autowired
private MockMvc mvc;
#Mock
private UsersService userService;
#InjectMocks
private UsersControllers usersController;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
this.mvc = MockMvcBuilders.standaloneSetup(usersController).build();
}
#Test
public void mustCreateANewUser() throws Exception {
NewUserDto userMock = new NewUserDto("firstname", "lastname", "login", "password");
when(userService.registerNewUser(any(NewUserDto.class)))
.thenReturn(CompletableFuture.completedFuture(null));
mvc.perform(post("/api/users/new")
.content(TestHelpers.convertToJson(userMock))
.contentType(TestHelpers.getJsonMediaType()))
.andExpect(status().isCreated());
}
}
TestHelpers.convertToJson and TestHelpers.getJsonMediaType are static methods.
public static MediaType getJsonMediaType() {
return new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
}
public static String convertToJson(Object o) throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(o);
}
I do not understand why the response code was 200 on unit test. In any part of my controller, service, or controller advice I have a response 200 OK.
The problem was because my controller and service are async, so my unit test it's not waiting for the correct response.
Changed my unit test to:
MvcResult result = mvc.perform(post("/api/users/new")
.content(TestHelpers.convertToJson(registroMock))
.contentType(TestHelpers.getJsonMediaType()))
.andReturn();
mvc.perform(asyncDispatch(result))
.andExpect(status().isCreated());
Hi I'm trying to implement junit in my controller. But what I get is 201 instead of 200.
Below is my controller
#RestController
#RequestMapping(value = "/treat")
public class TreatController {
private final TreatService treatService;
#Autowired
public TreatController(TreatService treatService){
this.treatService = treatService;
}
#PostMapping
public ResponseEntity<CommonResponse> addNew(
#RequestBody Treat treat) throws RecordNotFoundException{
CommonResponse response = new CommonResponse();
response.setStatus(CommonConstants.OK);
response.setData(treatService.save(treat));
return new ResponseEntity<>(response, HttpStatus.CREATED);
}
}
next is my Junit testing:
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest(TreatController.class)
public class TreatControllerTest {
private RecordNotFoundException recordException = new RecordNotFoundException("");
private final String title = "{\"title\" : \"title\"}";
#Autowired
private MockMvc mockMvc;
#MockBean
private TreatService treatService;
#Test
public void addNew() throws Exception{
Treatment treatment = new Treatment();
given(treatmentService.save(
Mockito.any(Treat.class))).willReturn(treat);
mockMvc.perform(post("/treats")
.content(title)
.accept(MediaType.APPLICATION_JSON_VALUE)
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andDo(print())
.andExpect(status().isOk());
Mockito.verify(treatService).save(Mockito.any(Treat.class));
}
}
is there anything that I missed?
By the way, I dont use Json. I just inserted it because it works.
That's what you return.
return new ResponseEntity<>(response, HttpStatus.CREATED);
HttpStatus.CREATED returns 201 and indicates that a resource has been created by the request
How ever in your testcase you are expecting OK(200) .andExpect(status().isOk());
According to HTTP1.1/ specs Post request should always result in the creation of a resource. So it makes sense to return 201 from there. All your need to do is change your testcase assertion expected value to HTTPStatus.CREATED.
I use Spring MVC and Spring boot to write a Restful service. This code works fine through postman.While when I do the unit test for the controller to accept a post request, the mocked myService will always initialize itself instead of return a mocked value defined by when...thenReturn... I use verify(MyService,times(1)).executeRule(any(MyRule.class)); and it shows the mock is not used.
I also tried to use standaloneSetup for mockMoc, but it complains it can't find the mapping for the path "/api/rule".
Could anybody help to figure out the problem?
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class MyControllerTest {
#Mock
private MyService myService;
#InjectMocks
private MyController myRulesController;
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void controllerTest() throws Exception{
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
Long userId=(long)12345;
MyRule happyRule = MyRule.createHappyRule(......);
List<myEvent> mockEvents=new ArrayList<myEvent>();
myEvents.add(new MyEvent(......));
when(myService.executeRule(any(MyRule.class))).thenReturn(mockEvents);
String requestBody = ow.writeValueAsString(happyRule);
MvcResult result = mockMvc.perform(post("/api/rule").contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andExpect(status().isOk())
.andExpect(
content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
verify(MyService,times(1)).executeRule(any(MyRule.class));
String jsonString = result.getResponse().getContentAsString();
}
}
Below is my controller class, where MyService is a interface. And I have implemented this interface.
#RestController
#RequestMapping("/api/rule")
public class MyController {
#Autowired
private MyService myService;
#RequestMapping(method = RequestMethod.POST,consumes = "application/json",produces = "application/json")
public List<MyEvent> eventsForRule(#RequestBody MyRule myRule) {
return myService.executeRule(myRule);
}
}
Is api your context root of the application? If so remove the context root from the request URI and test. Passing the context root will throw a 404. If you intend to pass the context root then please refer the below test case. Hope this helps.
#RunWith(MockitoJUnitRunner.class)
public class MyControllerTest {
#InjectMocks
private MyController myRulesController;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = standaloneSetup(myRulesController).build();
}
#Test
public void controllerTest() throws Exception{
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
MyController.User user = new MyController.User("test-user");
ow.writeValueAsString(user);
MvcResult result = mockMvc.perform(post("/api/rule").contentType(MediaType.APPLICATION_JSON).contextPath("/api")
.content(ow.writeValueAsString(user)))
.andExpect(status().isOk())
.andExpect(
content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
}
}
Below is the controller
/**
* Created by schinta6 on 4/26/16.
*/
#RestController
#RequestMapping("/api/rule")
public class MyController {
#RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
public User eventsForRule(#RequestBody User payload) {
return new User("Test-user");
}
public static class User {
private String name;
public User(String name){
this.name = name;
}
}
}