Ice
Ice

Reputation: 1971

TDD test for Spring MVC controller not working correctly

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?

Upvotes: 0

Views: 235

Answers (1)

JB Nizet
JB Nizet

Reputation: 691775

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.

Upvotes: 2

Related Questions