I need to test one method in RestController, with mock class. But java does not understand, then its mock class and try invoke it. However, such method with the same mock class works sucsesfuly.
My RestController:
#RestController
public class OrderController {
#Autowired
ServiceOrder serviceOrder;
#PreAuthorize("hasRole('ROLE_ADMIN')")
#RequestMapping(value = "/orders", method= RequestMethod.POST, produces={"application/json; charset=UTF-8"})
public List<Order> sortOrders(#RequestParam("field") String field) {
return serviceOrder.sortOrders(field);
#PreAuthorize("hasRole('ROLE_ADMIN')")
#RequestMapping(value = "/orders/completed/period", method= RequestMethod.POST, produces={"application/json"})
public long showCompletedOrdersInPer(
#RequestParam (value = "start") String startDate,
#RequestParam (value = "end") String endDate) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate start = LocalDate.parse(startDate, formatter);
LocalDate end = LocalDate.parse(endDate, formatter);
return serviceOrder.completedOrdersInPeriod(start, end);
}
Well, test for method sortOrders() is OK, but test for showCompletedOrdersInPer() is failed.
My test class:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {ControllersTestConfig.class})
#WebAppConfiguration
public class OrderControllerTest {
#Autowired
private WebApplicationContext webApplicationContext;
#Autowired
OrderController orderController;
#Autowired
ServiceOrder serviceOrder;
private MockMvc mockMvc;
#BeforeEach
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
}
// Test from method OrderController.sortOrders
// Description: we should get response.status OK
#Test
public void sortOrdersTest() throws Exception {
Mockito.when(serviceOrder.sortOrders(any())).thenReturn(null);
mockMvc.perform(MockMvcRequestBuilders.post("/orders?field=1")).andExpect(MockMvcResultMatchers.status().isOk());
}
// Test from method OrderController.showCompletedOrdersInPer
// Description: we should get response.status OK
#Test
public void showCompletedOrdersInPerTest() throws Exception {
Mockito.when(serviceOrder.completedOrdersInPeriod(any(), any())).thenReturn(1L);
mockMvc.perform(MockMvcRequestBuilders.post("/orders/completed/period?start=2020-01-01&end=2022-01-01")).andExpect(MockMvcResultMatchers.status().isOk());
}
And this is configClass:
public class ControllersTestConfig {
#Bean
public ServiceOrder serviceOrder() {
return Mockito.mock(ServiceOrder.class);
}
#Bean
public OrderController orderController(){
return new OrderController();
}
}
When i run sortOrdersTest(), test is ok, when i run showCompletedOrdersInPerTest(), i have
Status expected:<200> but was:<500>
Expected :200
Actual :500
If i run tests with debug, i see, then in sortOrders() mock works and serviceOrder.sortOrders(field) does not invoke, and in showCompletedOrdersInPer() mock does not work and java try invoke serviceOrder.completedOrdersInPeriod(start, end) and i have status 500.
Please, help me!
Well, it was a problem with parsing Integer to Long in dao layer. I resolve it and test is done.
Related
I'm making test code in spring boot.
But, my test code doesn't save the data using #Before method.
If i request to '/v1/stay/, it return empty array...
Please can you explain what is wrong with my code?
Here is my test code.
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class StayControllerTest {
#MockBean
private StayService stayService;
#Autowired
private MockMvc mockMvc;
// givenStay method is the method generating dummy data
#Before
public void before() {
stayService.save(givenStay1());
stayService.save(givenStay2());
stayService.save(givenStay3());
stayService.save(givenStay4());
stayService.save(givenStay5());
}
#Test
#Transactional
void showStayList() throws Exception {
List<StayReq> original = new ArrayList<>();
original.add(givenStay1());
original.add(givenStay2());
original.add(givenStay3());
original.add(givenStay4());
original.add(givenStay5());
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/v1/stay")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print())
.andReturn();
System.out.println(result.getResponse());
}
}
And below code blocks are my StayController and StayService
#RestController
#ApiV1
#RequiredArgsConstructor
public class StayController {
private final StayService stayService;
private final ApiService apiService;
#GetMapping("/stay")
public ResponseEntity<Response> stayList() {
return apiService.okResponse(stayService.getList());
}
}
#Service
#RequiredArgsConstructor
public class StayService {
private final StayRepository stayRepository;
private final RoomRepository roomRepository;
public List<StayRes> getList() {
return stayRepository.findAll().stream().map(StayRes::new).collect(Collectors.toList());
}
#Transactional
public void save(StayReq stayReq) {
stayRepository.save(stayReq.toEntity());
}
}
You injected a mock, not a 'real' service. If you want to use a 'real' service - you need to replace #MockBean annotation with #Autowired annotation.
Or alternatively - you can configure mock in the test method to return some predefined data.
I want to create JUnit test for Rest api and generate api doc. I want to test this code:
Rest controller
#RestController
#RequestMapping("/transactions")
public class PaymentTransactionsController {
#Autowired
private PaymentTransactionRepository transactionRepository;
#GetMapping("{id}")
public ResponseEntity<?> get(#PathVariable String id) {
return transactionRepository
.findById(Integer.parseInt(id))
.map(mapper::toDTO)
.map(ResponseEntity::ok)
.orElseGet(() -> notFound().build());
}
}
Repository interface
public interface PaymentTransactionRepository extends CrudRepository<PaymentTransactions, Integer>, JpaSpecificationExecutor<PaymentTransactions> {
Optional<PaymentTransactions> findById(Integer id);
}
I tried to implement this JUnit5 test with mockito:
#ExtendWith({ RestDocumentationExtension.class, SpringExtension.class })
#SpringBootTest(classes = PaymentTransactionsController.class)
#WebAppConfiguration
public class PaymentTransactionRepositoryIntegrationTest {
.....
private MockMvc mockMvc;
#MockBean
private PaymentTransactionRepository transactionRepository;
#BeforeEach
void setUp(WebApplicationContext webApplicationContext,
RestDocumentationContextProvider restDocumentation) {
PaymentTransactions obj = new PaymentTransactions(1);
Optional<PaymentTransactions> optional = Optional.of(obj);
PaymentTransactionRepository processor = Mockito.mock(PaymentTransactionRepository.class);
Mockito.when(processor.findById(Integer.parseInt("1"))).thenReturn(optional);
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.alwaysDo(document("{method-name}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())))
.build();
}
#Test
public void testNotNull() {
assertNotNull(target);
}
#Test
public void testFindByIdFound() {
Optional<PaymentTransactions> res = target.findById(Integer.parseInt("1"));
// assertTrue(res.isPresent());
}
#Test
public void indexExample() throws Exception {
this.mockMvc.perform(get("/transactions").param("id", "1"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/xml;charset=UTF-8"))
.andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")),
responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))));
}
}
I get error:
java.lang.AssertionError: Status expected:<200> but was:<404>
What his the proper way to to make GET request to the above code?
Probably I need to add response OK when message is send back?
hi in my case i needed #MockBean of controller and all services that is was autowireing ;)
Instead of #PostMapping and #GetMapping which caused same problem while #RequestMapping in controller helped
It's a path variable, so instead of using param value, please use path variable.
For MvcResult import, you can import org.springframework.test.web.servlet
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
...
given(target.findById(anyInt())).willReturn(Optional.of(new PaymentTransactions(1))).andReturn();
MvcResult result = this.mockMvc.perform(get("/transactions/1")
.accept("application/xml;charset=UTF-8")).andReturn();
String content = result.getResponse().getContentAsString();
this.mockMvc.perform(get("/transactions/1")
.accept("application/xml;charset=UTF-8"))
.andExpect(status().isOk())
.andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")),
responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))));
Can you try this..
public class PaymentTransactionsControllerTest {
private MockMvc mvc;
#InjectMocks
PaymentTransactionsController paymentTransactionsController;
#MockBean
private PaymentTransactionRepository processor;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(paymentTransactionsController).build();
}
#Test
public void indexExample() throws Exception {
PaymentTransactions obj = new PaymentTransactions(1);
Optional<PaymentTransactions> optional = Optional.of(obj);
Mockito.when(processor.findById(Integer.parseInt("1"))).thenReturn(optional);
MvcResult result = mvc.perform(MockMvcRequestBuilders.get("/transactions/{id}", 1))
.andDo(print())
.andExpect(status().isOk())
.andReturn();
Assert.assertNotNull(result.getResponse().getContentAsString());
}
}
I have a actually create simple webservice and i want to add new junit test.
I have a method where I add people to teams.
This is my method(in rest controller):
#PostMapping("/addPeopleToTeams/{teamId}/{personId}")
#ResponseBody
public ResponseEntity<?> addPeopleToTeam(#PathVariable Long teamId, #PathVariable Long personId) {
TeamsAndPersonsId teamsAndPersonsId = new TeamsAndPersonsId(personId, teamId);
teamService.findTeamById(teamsAndPersonsId.getTeamId());
personService.findById(teamsAndPersonsId.getPersonId());
teamService.addPersonsToTeams(personId, teamId);
return ResponseEntity.ok(teamsAndPersonsId);
}
For this method i want to wrote a Junit test but something is going wrong:/
This is my test class with method:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class TeamControllerTest {
private ObjectMapper mappingObject = new ObjectMapper();
private MockMvc mockMvc;
#Mock
private TeamService teamService;
private PersonService personService;
#Before
public void initTest() {
mockMvc = MockMvcBuilders
.standaloneSetup(new TeamController(teamService, personService))
.setControllerAdvice(GlobalExceptionHandler.class)
.build();
}
#Test
public void shouldAddPersonToTeam() throws Exception{
TeamDto teamDto = prepareTeamDto();
PersonDto personDto = new PersonDto(1L, "Bob", "Noob", "mail#first.pl", "Warszawa", "APPS", "Developer");
doNothing().when(teamService).createTeam(teamDto);
doNothing().when(personService).addPerson(personDto);
mockMvc.perform(post("/addPeopleToTeams/{teamId}/{personId}",1,1))
.andExpect(status().isOk());
}
private TeamDto prepareTeamDto() {
return new TeamDto(1L, "Jan", "local", "wawa", 6);
}
Actually for this method i have this error:
org.mockito.exceptions.base.MockitoException:
Only void methods can doNothing()!
Example of correct use of doNothing():
doNothing().
doThrow(new RuntimeException())
.when(mock).someVoidMethod();
Above means:
someVoidMethod() does nothing the 1st time but throws an exception the 2nd time is called
doNothing() is used only for void methods, like is described in your error message, in your case you have to use something like:
when(teamService.createTeam(teamDto)).thenReturn(Reponse.ok().build());
Note: you have to override #equals method in your TeamDto class
Based on the error, I guess that TeamService.createTeam or PersonService.addPerson does not have void return type and you can mock doNothing behaviour only on methods, which returns void. Also you are missing #Mock annotation on PersonService field.
In spring boot tests, it is better to use #MockBean annotation. And for controller tests it is better to use #WebMvcTest, you can then skip the configuration done in your setup method:)
#InjectMocks
Controller controllerMock;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controllerMock).build();
}
where - ControllerMock will be Mock of Controller class
I am creating my first unit test, and just wanted to create something pretty simple based on one of the Spring tutorials.
Here is the error I am getting:
java.lang.AssertionError: Response content
Expected: (null or an empty string)
but: was "Debug"
My Controller:
#RestController
#RequestMapping(value = "/person")
public class PersonController {
#Autowired
protected PersonService personService;
#RequestMapping(value = "/lastName", produces = "application/json")
public String lastName(#RequestParam(value = "cid") String cid)
{
return personService.findByCId(cid).getLastName();
}
My Test:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class MvcLastNameTest {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldReturnNonNullString() throws Exception {
this.mockMvc.perform(get("/person/lastName?cid=123456")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(isEmptyOrNullString()));
}
}
in your test your are expecting EmptyOrNullString, but your controller produces a lastName
change your expectation:
.andExpect(content().string("Debug")); // or any other valid lastName
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;
}
}
}