Spring MVC 控制器的 TDD 测试无法正常工作

TDD test for Spring MVC controller not working correctly

我创建了我的第一个 Spring MVC、Boot、Data 网络应用程序,但我在创建测试时遇到了问题。我只是修改了 Craig Wall 书中的一些示例 "Spring in Action"。 我尝试为我的控制器编写 TDD 测试,方法 registerNewAccount,我确信一切正常,但我总是得到 argumetns are different!。完整堆栈跟踪如下:

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)

我的控制器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:/";
    }

}

我的服务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);
    }
}

我的仓库Class:

@Component
public interface AccountRepository extends CrudRepository<Account, Long>{

}

还有我的规格 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","m@gmail.com");
        Account saved = new Account("M","B","m@gmail.com");

        when(service.create(unsaved)).thenReturn(saved);

            mockMvc.perform(post("/account/register")
                    .param("firstName","M")
                    .param("lastName","B")
                    .param("email","m@gmail.com"))
                    .andExpect(redirectedUrl("/"));


        verify(service,atLeastOnce()).create(unsaved);
    }
}

我做错了什么?

您希望我们的控制器使用 unsaved 帐户调用您的服务。但是当您调用您的控制器时,Spring 根据请求中发送的参数创建一个新的 Account 实例,并使用该 Account 调用服务,这不等于 unsaved.

因此,要么定义 equals() 和 hashCode(),以便 Spring 创建的实际实例等于 unsaved,要么使用另一个接受任何帐户的匹配器,或者使用一个 ArgumentCaptor 来捕获您的服务传递的实际帐户,并检查它是否具有预期的属性。