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

时间:2017-01-15 16:16:44

标签: spring spring-mvc spring-boot tdd

我创建了我的第一个Spring MVC,Boot,Data web-app,当我想创建测试时,我遇到了问题。我只修改了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)

我的控制器类:

@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:/";
    }

}

我的服务类:

@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);
    }
}

我的存储库类:

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

}

我的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","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);
    }
}

我做错了什么?

1 个答案:

答案 0 :(得分:2)

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

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