所以我开始抓住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);
}
非常自我解释。
然后我有以下测试套件
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()
那过度杀人吗?我甚至没有展示过服务测试!
我可以剔除哪些(如果有的话)?
TIA,
查尔斯
答案 0 :(得分:17)
这完全取决于您需要/需要的覆盖范围以及可靠性是多少。
以下是您应该问自己的问题:
关于第三个,我记得当我开始编写单元测试时(我知道,与TDD不同)我会进行类似的测试:
string expected, actual;
TypeUnderTest target = new TypeUnderTest();
target.PropertyToTest = expected;
actual = target.PropertyToTest;
Assert.AreEqual<string>(expected, actual);
我可以用我的时间做更高效的事情,例如为我的桌面选择更好的壁纸。
我推荐ASP.net MVC书籍作者Sanderson的这篇文章:
http://blog.codeville.net/2009/08/24/writing-great-unit-tests-best-and-worst-practises/
答案 1 :(得分:5)
我会说你做得比你可能要多一点。虽然测试代码可能采用的每个可能路径都很好,但某些路径不是很重要,或者不会导致行为的真正差异。
在您的示例中,使用LogOn(string returnUrl)
您要做的第一件事是检查returnUrl参数,如果它为null / empty,则将其重新分配给默认值。你真的需要一个完整的单元测试来确保一行代码按预期发生吗?这不是一条容易破裂的路线。
可能会破坏该行的大多数更改都会导致编译错误。可以在该行中更改所分配的默认值(可能您稍后决定“/”不是一个好的默认值...但在您的单元测试中,我打赌您硬编码以检查“/” “不是吗?因此,价值的变化将需要改变你的测试......这意味着你没有测试你的行为,而是测试你的数据。
您可以通过简单地使用一个不提供参数的测试来测试方法的行为。这将触及例程的“设置默认”部分,同时仍然测试其余代码的行为也是如此。
答案 2 :(得分:3)
看起来对我来说是正确的。是的,你会写很多单元测试,最初看起来像矫枉过正和TBH浪费时间;但坚持下去,这是值得的。你应该瞄准的是(而不仅仅是100%的代码覆盖率)是100%的功能覆盖率。但是......如果你发现你为同一个方法编写了很多UT,那么这个方法可能做得太多了。尝试更多地分离您的顾虑。根据我的经验,行动的主体应该做的不仅仅是新建一个班级来完成真正的工作。你应该真正用UT来定位这个类。
克里斯
答案 3 :(得分:2)
我只对我不确定的代码进行单元测试。当然 - 你永远不会知道什么会反击你,但为琐碎的事情编写测试对我来说似乎是一种矫枉过正。
我不是单元测试/ tdd大师 - 但我认为如果你不编写测试就可以了。它们必须有用。如果您对单元测试有足够的经验 - 那么当它们变得有价值时,您就会开始感觉。
您可能会喜欢this book。
编辑:
实际上 - 我刚刚在隔离框架章节下面找到了关于这个的引用。这是关于过度指定测试(一个特定测试),但我想这个想法仍然在更全球范围内:
过度指定测试
如果您的测试有太多期望,您可以创建一个测试 即使是最轻微的代码更改也会崩溃 整体功能仍然有效。考虑一下这种技术方式 没有验证正确的事情。测试交互是一个双刃剑 剑:测试太多,你开始忽视大局 - 整体功能;测试它太少了,你会想念的 对象之间的重要互动。
答案 4 :(得分:2)
100%的覆盖率是非常理想的,但是如果您必须大规模重构代码,它真的很有用,因为测试将控制您的代码规范以确保它是正确的。
我个人不是100%TDD(有时也太懒)但是如果你打算做100%,也许你应该写一些测试助手来消除这些重复测试的负担。例如,编写一个帮助程序来测试标准发布结构中的所有CRUD并使用回调来允许您传递一些评估可能会为您节省大量时间。