So I'm writing this web app with Spring Boot using Spring Data with JPA and Spring MVC and I would like to make mock controller tests. I figured out how to test the get method, but in my controllers post method a new JPA entity is being either persisted or updated with my service. Here is what my controller looks like:
@Controller
@RequestMapping("/registerMember")
public class RegisterMemberController {
@Autowired
private MemberService memberService;
@GetMapping
public String index(RegisterMemberBean registerMemberBean) {
return "registerMember";
}
@PostMapping
public String handleSubmit(@Valid RegisterMemberBean registerMemberBean, BindingResult bindingResult, Model model) {
Member member = registerMemberBean.getMember();
boolean isRepeatPasswordCorrect = !isRepeatPasswordIncorrect(member.getPassword(), registerMemberBean.getComparePassword());
if(isAnyErrors(isRepeatPasswordCorrect, !bindingResult.hasErrors())) {
if(!isRepeatPasswordCorrect) {
model.addAttribute("isRepeatPasswordIncorrect", true).
addAttribute("isRepeatPasswordIncorrectMsg", "Passwords don't match");
}
return "registerMember";
}
boolean errUsername = !memberService.isNoOtherEntityWithUserName(0, member.getUserName());
boolean errEmail = !memberService.isNoOtherEntityWithEmail(0, member.getEmail());
if(errUsername || errEmail) {
if(errUsername) {
model.addAttribute("isExistingUserName", true).addAttribute("isExistingUserNameMsg", "Already a user with that username");
} if(errEmail) {
model.addAttribute("isExistingEmail", true).addAttribute("isExistingEmailMsg", "Already a user with that email");
}
return "registerMember";
}
getMainService().save(member);
return redirectTo("index", new RedirectEntity("member", member.getId()));
}
}
Now in my mock controller test i want to make make sure that my post method does the following:
This is what my (poor) test class looks like so far:
@RunWith(SpringRunner.class)
@TestPropertySource(locations="classpath:application_test.properties")
@WebAppConfiguration
public class RegisterMemberControllerTest {
private MockMvc mockMvc;
@MockBean
private MemberService memberService;
@MockBean
private RegisterMemberController controller;
@Before
public void init() {
mockMvc = MockMvcBuilders.standaloneSetup(controller).setViewResolvers(new StandaloneMvcTestViewResolver()).build();
controller.setMainService(memberService);
}
@Test
public void testIndex() throws Exception {
mockMvc.perform(get("/registerMember"))
.andExpect(status().isOk())
.andExpect(forwardedUrl("registerMember");
}
@Test
public void testHandleSubmit() throws Exception {
RegisterMemberBean registerMemberBean = new RegisterMemberBean();
registerMemberBean.setMember(TestFixture.getValidMemberWithoutReferences());
Member member = TestFixture.getValidMember();
mockMvc.perform(post(Page.REGISTER_MEMBER)).andExpect(status().isOk());
when(mockMvc.perform(post(Page.REGISTER_MEMBER)).andExpect((ResultMatcher) memberService.save(member)).andExpect(forwardedUrl("redirect:/index/member=" + member.getId() + ".html")));
}
}
to my understanding spring boot uses Mockito. I have some experience with EasyMock but I would like to use the spring defaults as much as possible. Can someone show how to achieve this?
I think there is a little bit of confusion on what should and shouldn't be mocked.
If I read your question correctly, you are actually trying to Unit Test your RegisterMemberController
. Therefore, you most likely should NOT make a mock of that class, but actually test that class.
I believe that you would be creating fakes/dummies/stubs/mocks/spies of your MemberService
, RegisterMemberBean
, and BindingResult
classes.
It would be these classes that would be created by your unit test and handed to your controller during the test that will force the testing of the logic that you are interested in proving/disproving.
FYI, when verifying that the MemberService
class was called, that is where you would use a mock. The rest of the classes could either be dummies or stubs.
Side Note: I would recommend removing the Model parameter from your handleSubmit() method since it doesn't seem to be used anywhere.