以下哪个是编写单元测试并在ASP.NET MVC中继续使用TDD的更好方法

时间:2011-01-21 12:43:47

标签: asp.net-mvc unit-testing tdd

在阅读了很多MVC和测试驱动开发之后,我开始将我的webforms应用程序转换为MVC。我使用this书作为在ASP.NET MVC中学习TDD的参考之一。

该书的单元测试如下:

[TestMethod()]
public void Register_Can_Get_To_View()
{
    var target = new AccountController();
    var results = target.Register();
    Assert.IsNotNull(results);
    Assert.IsInstanceOfType(results, typeof(ViewResult));
    Assert.AreEqual("Register", target.ViewData["Title"]);
}

我也看了一下来自codeplex的nerddinner源代码,类似的单元测试编写如下

[TestMethod]
public void Index() 
{
    // Arrange
    HomeController controller = new HomeController();

    // Act
    ViewResult result = controller.Index() as ViewResult;

    // Assert
    Assert.IsNotNull(result);
}

在第一种情况下,作者正在将结果类型与ViewResult进行比较。但是在第二种情况下,结果将被转换为ViewResult并且未经过测试。

哪个更好,我是否需要真正详细测试,如第一种情况所示?

2 个答案:

答案 0 :(得分:4)

理想情况下,您可以针对可能出错的所有内容测试结果,null可能只是第一个。

您应该断言结果的所有值,并且实际上将从不同的角度(即使用不同的输入)测试它们,以便您测试这些结果是否与输入正确相关。 (即证明你没有对单个测试所需的值进行硬编码以使其通过)。

这个想法是:

  1. 编写一个无法编译的测试。
  2. 编写足够的以使其编译,但仍然失败(即NotImplementedException)。
  3. 编写足够的以使测试通过(您可以对要测试的设备进行硬编码以使测试通过)。
  4. 编写另一个失败的测试(这会强制您使用比硬编码更好的实现来考虑不同的输入)。
  5. 进行更改,以便测试再次通过。
  6. 重复操作,直到对设备进行全面测试(即考虑所有可能/合适的输入,并检查并妥善拒绝不合适的输入。)
  7. 有时你可以将第3步短路并写下肯特贝克所说的 明显的实施 ,因为你从经验中知道的事情将变得非常简单。你不会为复杂的单位做这个,但是对于一个反转字符串或将两个数字加在一起的方法,你可以继续正确编写实现。

    在这种情况下,我会考虑断言以下内容:

    • 控制器操作结果不为空。
    • Model属性的类型正确(假设强类型视图)。
    • Model上的每个属性或ViewData中的每个值都是给定输入的正确值。

答案 1 :(得分:1)

第一个测试看起来好像控制器操作正在使用ViewData而不是视图模型。对我来说这很糟糕。它使用魔术弦,非常脆弱。所以不再需要对它发表评论。

除了验证控制器操作是否返回视图外,第二个测试没有做任何有用的事情。

但更真实的世界控制器动作会将视图模型传递给此视图。所以你需要测试一下。我个人更喜欢MVCContrib TestHelper因为它使我的单元测试非常流畅和可读:

[TestMethod]
public void Index() 
{
    // Arrange
    var controller = new HomeController();

    // Act
    var actual = controller.Index();

    // Assert
    actual
        .AssertViewRendered()
        .WithViewData<MyViewModel>()
        .ShouldNotBeNull("the view model was null");
}

这里我们声明控制器操作呈现了一个视图,并且传递给它的视图模型不是null并且它是期望的类型,因为相应的视图将强烈地键入到该视图模型。