I creating my first Spring MVC, Boot, Data web-app and I have a problem when I want to create tests. I just modify some example from Craig Wall book "Spring in Action". I tried to write TDD test for my controller, for method registerNewAccount
, I was sure everything was ok, but all time I get argumetns are different!
. Full stack trace below:
Argument(s) are different! Wanted:
accountService.create(
com.conf.data.Account@2ed42a28
);
-> at com.conf.controller.AccountControllerSpec.registerNewUser(AccountControllerSpec.java:52)
Actual invocation has different arguments:
accountService.create(
com.conf.data.Account@2a4d1467
);
-> at com.conf.controller.AccountController.registerNewAccount(AccountController.java:32)
Argument(s) are different! Wanted:
accountService.create(
com.conf.data.Account@2ed42a28
);
-> at com.conf.controller.AccountControllerSpec.registerNewUser(AccountControllerSpec.java:52)
Actual invocation has different arguments:
accountService.create(
com.conf.data.Account@2a4d1467
);
-> at com.conf.controller.AccountController.registerNewAccount(AccountController.java:32)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
My Controller class:
@Controller
@RequestMapping(value = "/account")
public class AccountController {
private AccountService accountService;
@Autowired
public AccountController(AccountService accountService){
this.accountService = accountService;
}
@RequestMapping(value = "/register", method = RequestMethod.GET)
public String showRegistrationForm(){
return "account/register";
}
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerNewAccount(Account account){
accountService.create(account);
return "redirect:/";
}
}
My Service class:
@Service
@Transactional
public class AccountService {
private AccountRepository repository;
@Autowired
public AccountService(AccountRepository repository) {
this.repository = repository;
}
public Account create(Account account){
return repository.save(account);
}
}
My repository Class:
@Component
public interface AccountRepository extends CrudRepository<Account, Long>{
}
And my Spec Class:
public class AccountControllerSpec {
private MockMvc mockMvc;
private AccountService service;
private AccountController controller;
@Before
public void before(){
service = mock(AccountService.class);
controller = new AccountController(service);
mockMvc = standaloneSetup(controller).build();
}
@Test
public void registrationPage() throws Exception {
mockMvc.perform(get("/account/register")).andExpect(view().name("account/register"));
}
@Test
public void registerNewAccount() throws Exception {
Account unsaved = new Account("M","B","[email protected]");
Account saved = new Account("M","B","[email protected]");
when(service.create(unsaved)).thenReturn(saved);
mockMvc.perform(post("/account/register")
.param("firstName","M")
.param("lastName","B")
.param("email","[email protected]"))
.andExpect(redirectedUrl("/"));
verify(service,atLeastOnce()).create(unsaved);
}
}
What am I doing wrong?
You expect our controller to call your service with the unsaved
account. But when you invoke your controller, Spring creates a new Account instance from the parameters sent in the request, and invokes the service with that Account, which is not equal to unsaved
.
So, either define equals() and hashCode(), so that the actual instance created by Spring is equal to unsaved
, or use another matcher, which accepts any Account, or use an ArgumentCaptor to capture the actual Account passed by your service, and check that it has the expected properties.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments