MVC控制器动作单元测试的粒度

时间:2015-03-12 17:28:11

标签: asp.net-mvc unit-testing

假设我的动作看起来像这样:

...
var userInfo = authService.SignIn(signInModel.UserName, signInModel.Password);    

if (userInfo == null)
{
    ModelState.AddModelError("", "Invalid username/password");
    return RedirectToAction(MVC.Home.Index());
}

var userData = new UserData
{
    UserID = userInfo.UserID,
    Name = userInfo.Name,
    Email = userInfo.Email,
    Roles = userInfo.Roles
};

string serializedUserData = textSerializer.Serialize(userData);

formsAuthHelper.CreateAuthCookie(userInfo.UserName, serializedUserData);
...

我应该为每种情况编写单独的单元测试:

  • 验证是否已调用Serialize方法
  • 验证是否已调用CreateAuthCookie方法

或者我可以编写单个单元测试来验证上述两种情况吗?

2 个答案:

答案 0 :(得分:0)

我会为每个beahviour创建一个测试。一个用于验证对Serialize的调用,另一个用于调用CreateAuthCookie。

这样,如果在某个时刻删除了其中一个调用,您只需删除相应的单元测试,而无需编辑现有调用。

此外,如果您以

的形式使用测试的命名约定
void When_Calling_XXXX_With_YYYY_Then_ZZZZZ();

ZZZ部分将更具可读性

答案 1 :(得分:0)

我认为这完全是个人偏好,但我会在单个单元测试中验证两者。

我查看测试的方式是,给定某个上下文,可以获得一些结果。有时,这意味着需要调用多个方法或服务来实现该结果。设置auth cookie仅在Serialize()成功时才有意义,同样调用Serialize()的唯一原因是创建auth令牌。他们无法相互独立地运行,因此单元测试也不应该。 根据有效的用户名和密码,用户已登录。在这种情况下,它意味着您验证了用户的密码,并创建了包含必需数据的令牌。

另外,我认为实际上,所有的设置工作只是为了纯度"测试是浪费时间。其他答案提到如果您将来重构此操作,则更新测试的难易程度。根据我的经验,如果你重写它,那将是一个如此重大的变化,你无论如何都要重做测试。

有点偏离主题,但这就是我喜欢Machine.specifications测试框架的原因,因为您正在进行单一设置,但测试运行器会将您的每个验证视为单独的测试。

public class when_calling_login_with_a_valid_username_and_password
{
    Because of = () => controller.Login(...);

    It should_call_serialize = () => textSerializer.Serialize().MustHaveBeenCalled();
    It should_set_the_auth_token = () => formsAuthHelper.CreateAuthCookie().MustHaveBeenCalled()
}