ASP.NET MVC - 单元测试过度杀伤?(TDD)

Cha*_*ino 17 tdd asp.net-mvc unit-testing

所以我开始抓住TDD错误,但我想知道我是否真的做得对......我似乎在写很多测试.

越多的测试越好,当然,但我有一种感觉,我已经过度了.说实话,我不知道我能用多长时间来编写这些简单的重复测试.

例如,这些是来自我的AccountController的LogOn操作:

public ActionResult LogOn(string returnUrl)
{
    if (string.IsNullOrEmpty(returnUrl))
        returnUrl = "/";

    var viewModel = new LogOnForm()
    {
        ReturnUrl = returnUrl
    };

    return View("LogOn", viewModel);
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LogOn(LogOnForm logOnForm)
{
    try
    {
        if (ModelState.IsValid)
        {
            AccountService.LogOnValidate(logOnForm);

            FormsAuth.SignIn(logOnForm.Email, logOnForm.RememberMe);

            return Redirect(logOnForm.ReturnUrl);
        }
    }
    catch (DomainServiceException ex)
    {
        ex.BindToModelState(ModelState);
    }
    catch
    {
        ModelState.AddModelError("*", "There was server error trying to log on, try again. If your problem persists, please contact us.");
    }

    return View("LogOn", logOnForm);
}
Run Code Online (Sandbox Code Playgroud)

非常自我解释.

然后,我有以下测试套件

public void LogOn_Default_ReturnsLogOnView()
public void LogOn_Default_SetsViewDataModel()
public void LogOn_ReturnUrlPassedIn_ViewDataReturnUrlSet()
public void LogOn_ReturnUrlNotPassedIn_ViewDataReturnUrDefaults()
public void LogOnPost_InvalidBinding_ReturnsLogOnViewWithInvalidModelState()
public void LogOnPost_InvalidBinding_DoesntCallAccountServiceLogOnValidate()
public void LogOnPost_ValidBinding_CallsAccountServiceLogOnValidate()
public void LogOnPost_ValidBindingButAccountServiceThrows_ReturnsLogOnViewWithInvalidModelState()
public void LogOnPost_ValidBindingButAccountServiceThrows_DoesntCallFormsAuthServiceSignIn()
public void LogOnPost_ValidBindingAndValidModelButFormsAuthThrows_ReturnsLogOnViewWithInvalidModelState()
public void LogOnPost_ValidBindingAndValidModel_CallsFormsAuthServiceSignIn()
public void LogOnPost_ValidBindingAndValidModel_RedirectsToReturnUrl()
Run Code Online (Sandbox Code Playgroud)

这是杀了吗?我甚至没有展示过服务测试!

我可以剔除哪些(如果有的话)?

TIA,
查尔斯

TJB*_*TJB 17

这一切都取决于您需要/想要的覆盖范围以及可靠性是多少.

以下是您应该问自己的问题:

  • 此单元测试是否有助于实现我尚未拥有的功能/代码更改?
  • 如果我稍后进行更改,此单元测试是否有助于回归测试/调试此单元?
  • 满足此单元测试的代码是否非常重要或是否值得进行单元测试?

关于第三个,我记得当我开始编写单元测试时(我知道,与TDD不同)我会进行如下测试:

string expected, actual;
TypeUnderTest target = new TypeUnderTest();
target.PropertyToTest = expected;
actual = target.PropertyToTest;
Assert.AreEqual<string>(expected, actual);
Run Code Online (Sandbox Code Playgroud)

我可以用我的时间做更高效的事情,比如为我的桌面选择更好的壁纸.

我推荐ASP.net MVC书籍作者Sanderson的这篇文章:

http://blog.codeville.net/2009/08/24/writing-great-unit-tests-best-and-worst-practises/


Ste*_*edd 5

我会说你做得比你可能要多一点.虽然测试代码可能采用的每个可能路径都很好,但某些路径不是很重要,或者不会导致行为的真正差异.

在你的例子中取LogOn(string returnUrl)

您在那里做的第一件事是检查returnUrl参数,如果它为null/empty,则将其重新分配给默认值.你真的需要一个完整的单元测试来确保一行代码按预期发生吗?这不是一条容易破裂的路线.

可能会破坏该行的大多数更改都会导致编译错误.可以在该行中更改所分配的默认值(可能您稍后决定"/"不是一个好的默认值...但在您的单元测试中,我打赌您硬编码以检查"/" "不是吗?因此,价值的变化将需要改变你的测试......这意味着你没有测试你的行为,而是测试你的数据.

您可以通过简单地使用一个不提供参数的测试来测试方法的行为.这将触及例程的"设置默认"部分,同时仍然测试其余代码也表现良好.