I'm new to unit tests and well, I'm struggling to understand how it should be done.
I have some methods with #RequestParam and I'm not sure how to mock this.
It would be great if I had an example I could apply to the other methods.
Could you help me by writing the test method for this one? It would be very useful.
#PutMapping("/player/update-password")
public ResponseEntity<?> updatePlayerPassword(#RequestParam("token") String token, #RequestParam("password") String newPassword) throws URISyntaxException {
String message = bundle.getString("put_player");
log.debug(message, token, newPassword);
PlayerEntity player = playerService.updatePassword(token, newPassword);
return new ResponseEntity<>(PlayerMapper.INSTANCE.mapPlayer(player), HttpStatus.ACCEPTED);
}
Thanks.
You can use #Mock and #InjectMocks annotations. With it you can inject mocks to your controller.
#Mock
PlayerService playerServiceMock;
And use when().then() from Mockito inside test or method with #Before annotation:
when(playerServiceMock.updatePassword(anyString(), anyString())).thenReturn(playerEntity);
The same can be done for bundle.getString("put_player").
Hoping you are using the Mockito. You can try the below code, need to add all imports
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class YourClassNameTest {
#Autowired
MockMvc mockMvc;
#InjectMocks
YourClassName yourClassName;
#Mock
PlayerService playerService;
#Before
public void Setup() {
mockMvc = MockMvcBuilders.standaloneSetup(yourClassName);
}
#Test
public void updatePlayerPasswordTest() throws Exception {
PlayerEntity player = new PlayerEntity();
// set some date if you want
Mockito.when(playerService.updatePassword(anyString(), anyString())).thenReturn(player);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.get("/player/update-password?token=abc&password=test")
.accept(MediaType.APPLICATION_JSON);
mockMvc.perform(requestBuilder).andExpect(MockMvcResultMatchers.status().isCreated());
}
}
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've been trying to figure out why my mocked findIngredientsByCategory method is returning null when I have when(controller.findIngredientsByCategory(any()).thenReturn(Collections.emptyList()). This implementation works for the findAll method works.
Below is my implementation for my unit test:
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest(IngredientController.class)
#ContextConfiguration(classes = {TestContext.class, WebApplicationContext.class})
#WebAppConfiguration
public class IngredientControllerTest {
#Autowired
private WebApplicationContext context;
#Autowired
private MockMvc mvc;
#MockBean
private IngredientController ingredientController;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.webAppContextSetup(context).build();
}
#Autowired
private ObjectMapper mapper;
private static class Behavior {
IngredientController ingredientController;
public static Behavior set(IngredientController ingredientController) {
Behavior behavior = new Behavior();
behavior.ingredientController = ingredientController;
return behavior;
}
public Behavior hasNoIngredients() {
when(ingredientController.getAllIngredients()).thenReturn(Collections.emptyList());
when(ingredientController.getIngredientsByCategory(any())).thenReturn(Collections.emptyList());
when(ingredientController.getIngredientById(anyString())).thenReturn(Optional.empty());
return this;
}
}
#Test
public void getIngredientsByCategoryNoIngredients() throws Exception {
Behavior.set(ingredientController).hasNoIngredients();
MvcResult result = mvc.perform(get("/ingredients/filter=meat"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andReturn();
String content = result.getResponse().getContentAsString();
System.out.println(content);
}
And below is the implementation for the controller:
#RestController
#RequestMapping("/ingredients")
public class IngredientController {
#Autowired
private IngredientRepository repository;
#RequestMapping(value = "/filter", method = RequestMethod.GET)
public List getIngredientsByCategory(#RequestParam("category") String category) {
return repository.findByCategory(category);
}
}
I'm not sure why the mock controller is returning null with this request, when I tell it to return an empty list. If someone could please help with this I would greatly appreciate it! Thanks.
Th request path in test is "/ingredients/filter=meat", but it should be "/ingredients/filter?category=meat". So, it seem that getIngredientsByCategory was not called.
The MockMvc actually will call the IngredientController that is bootstrapped and created by the Spring Test framework but not call the mocked IngredientController that you annotated with #MockBean, so all the stubbing that you made will not be called.
Actually, the point of #WebMvcTest is to test #RestController and its related Spring configuration is configured properly , so a real instance of IngredientController is necessary to create rather than using a mocked one. Instead , you should mock the dependencies inside IngredientController (i.e IngredientRepository).
So , the codes should looks like:
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest(IngredientController.class)
#ContextConfiguration(classes = {TestContext.class, WebApplicationContext.class})
#WebAppConfiguration
public class IngredientControllerTest {
#Autowired
private WebApplicationContext context;
#Autowired
private MockMvc mvc;
#MockBean
private IngredientRepository ingredientRepository;
#Test
public void fooTest(){
when(ingredientRepository.findByCategory(any()).thenReturn(Collections.emptyList())
//And use the MockMvc to send a request to the controller,
//and then assert the returned MvcResult
}
}
I am trying to test my REST endpoints using RestAssured with mocking some of the service/repositories in the controller.
this is my test class:
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {VedicaConfig.class})
#AutoConfigureMockMvc
#ActiveProfiles("test")
public class RESTTest {
#LocalServerPort
private int port;
#Autowired
private MockMvc mvc;
#Mock
MetaVersionDAO metaVersionDAO;
#InjectMocks
DocCtrl docCtrl;
#Before
public void contextLoads() {
RestAssured.port = port;
assertThat(mvc).isNotNull();
// this must be called for the #Mock annotations above to be processed.
MockitoAnnotations.initMocks(this);
RestAssuredMockMvc.standaloneSetup(MockMvcBuilders.standaloneSetup(docCtrl));
}
#Test
public void shouldGetThumbnail() {
String ver = "1.0";
String uuid = "124-wqer-365-asdf";
when(metaVersionDAO.getMetaByVersionUUID(ver, uuid)).thenReturn(new DocVersion());
given()
.when()
.param("uuid", uuid)
.param("versionVed", ver)
.get(CTX_BASE + "/thumbnail")
.then()
.log().ifValidationFails()
.statusCode(OK.value())
.contentType(ContentType.BINARY);
}
}
now, the REST endpoint itself is being hit correctly with supplied parameters. this endpoint has DocCtrl injected which uses metaVersionDAO instance in turn:
public RawDocument getDocThumbnail(String uuid, String versionVed) throws Exception {
DocVersion docVersion = metaVersionDAO.getMetaByVersionUUID(versionVed, uuid);
InputStream inputStream = okmWebSrv.getOkmService().getContentByVersion(uuid, versionVed);
String dataType = docVersion.getMetadata().getAdditionals().get(Vedantas.CONTENT_TYPE);
ByteArrayInputStream bais = new ByteArrayInputStream(createPDFThumbnail(dataType, inputStream));
RawDocument rawDocument = new RawDocument(bais, "qwer");
return rawDocument;
}
as you can see, I have tried to mock metaVersionDAO at the top of the #Test method so I expected it to return new DocVersion() as I set it to, but in this DAO the actual code is being called and it fails on entityManager which is null.
My question is why metaVersionDAO.getMetaByVersionUUID doesn't return my mocked object and what should I do to make it so?
spring-mock-mvc: 3.3.0
spring-boot: 2.1.2.RELEASE
Thanks!
solved by changing #Mock for #MockBean.
so it is:
#MockBean
MetaVersionDAO metaVersionDAO;
everything else remains the same as in the post and it uses mocked instance.
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
As I mention in title, I need to create integration test.
This is my first test in my life.
I need that my integration test call a rest method but I'm getting this error:
This is My test:
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = CrewApplication.class)
#AutoConfigureMockMvc
#TestPropertySource(locations = "classpath:TeamController")
public class TeamIntegrationTest {
#Autowired
MockMvc mockMvc;
#Test
public void integrationTeamTest() throws Exception {
MvcResult mvcResult = mockMvc.perform(
MockMvcRequestBuilders.get("/teams")
.accept(MediaType.APPLICATION_JSON)
).andReturn();
System.out.println(mvcResult.getResponse());
}
}
And this is my rest method:
#RestController
public class TeamController {
private final TeamService teamService;
private final PersonService personService;
#Autowired
public TeamController(TeamService teamService, PersonService personService) {
this.teamService = teamService;
this.personService = personService;
}
#GetMapping("/teams")
public List<TeamDto> findAll() {
return teamService.findAll();
}
Method work, Junit test work only this integration throw error :
java.lang.NullPointerException
You are mixing Spring unit tests and Spring integration test.
When you want to do an Integrations test you have to actually make a call to the API.
#RunWith(SpringRunner.class)
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = CrewApplication.class)
public class TeamIntegrationTest {
#Autowired
private TestRestTemplate restTemplate;
#Test
public void integrationTeamTest() throws Exception {
String body = this.restTemplate.getForObject("/teams", String.class);
assertThat(body).isEqualTo("TEAM REPRESENTATION AS STRING");
}
}
If you need further information, visit Spring Documentation .