我应该测试不调用方法吗?

时间:2011-12-20 14:24:50

标签: unit-testing language-agnostic tdd

假设我有这段代码:

[HttpPost]
public ActionResult Edit(MyViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        _myRepository.SaveStuff(viewModel.Property1, viewModel.Property2);
        return RedirectToAction("MyAction", "MyController");
    }
    else
    {
        return View("Edit", viewModel);
    }
}

这是ASP.NET MVC,但这实际上与我的问题无关。真正的一点是,只有满足需求时才会调用方法(SaveStuff)。现在我想为这种方法编写单元测试......

我测试了调用存储库中的方法,并在modelstate有效时返回RedirectToRoute。我测试当模型状态无效时返回ViewResult。

我的问题是,我是否还应该编写一个测试,以确保当模型状态无效时,存储库中的方法是而不是这似乎是一个好的测试必须确保我没有得到任何不需要的保存。但是我觉得,如果我沿着这条路走下去,测试那些事情就不会发生,我必须写的测试数量会增加很多......

6 个答案:

答案 0 :(得分:4)

该方法有多少路径?

测试它们是否有意义?如果模型状态无效,保存它会是错误吗?

确保发生的事情的数量通常受到被测方法的背景的限制;如果模型无效(我假设),则重要的是不保存模型。

答案 1 :(得分:4)

回答你的问题,是的。你应该测试一个方法在不应该调用时不会被调用。您绝对不希望您的应用程序持久存储无效数据。

如果将所有内容分解为单独的测试,那么测试的数量也会增加,这也是正确的。您的测试可以有多个断言。当状态无效时,我会将两个断言结合起来。这将使你免于编写几乎相同的测试。

答案 2 :(得分:1)

  

我的问题是,我是否还应该编写一个测试,以确保当模型状态无效时,不会调用存储库中的方法?这似乎是一个很好的测试,必须确保我没有得到任何不必要的保存。但是我觉得,如果我沿着这条路走下去,测试那些事情就不会发生,我必须写的测试数量会增加很多......

我的答案一般都是肯定的,但你真的应该考虑测试的是你的。你应该测试任何让你担心的事情。

在这种情况下,只添加一个测试。它不应该添加很多。

答案 3 :(得分:1)

您想测试所有代码路径。如果它真的不会发生那么你甚至不需要if声明吗?我希望你为这个方法写两个测试:

// Note: I don't do .NET, so pardon any basic errors
// and hopefully the intent shows through.

[SetUp]
public void SetUp()
{
   repository = new MockWidgetRepository()
   controller = new WidgetController(repository);
}

[Test]
public void savesValidWidgets() 
{
   var result = controller.Edit(new ValidViewModel());
   Assert.IsTrue(repository.SaveWasCalled());
   Assert.AreEqual(typeof(RedirectResult), result.GetType());
}

这代表了你提到的第一个案例。然而,第二个是相似的。

[Test]
public void InvalidWidgetsAreRedisplayed()
{
   var result = controller.Edit(new InvalidViewModel());
   Assert.AreEqual(typeof(ViewResult), result.GetType());
}

希望有所帮助!

布兰登

答案 4 :(得分:0)

是的,但是我测试它的方式是有两个测试用例,一个是有效的,一个是无效的,当你运行每个case记录时,被测试代码所要求的保存顺序。

对于每个测试用例,检查它是否导致正确的保存顺序 - 对于有效案例恰好完全一次保存(使用正确的参数),并且完全零保存。

我的一般原因是,在可能的情况下,最好为每个被测代码区别对待的案例提供不同的测试代码。如果你有不同的测试数据通过相同的测试代码运行,那么当你编写测试代码时,你将弄乱你在应用程序代码中搞砸的相同边缘情况。因此,我尝试使用“放入此输入并检查输出和副作用是否符合预期”形式的公共代码来构造尽可能多的给定函数的测试。希望您最终能够以这种方式减少测试代码,因为您系统地测试所有输入的所有副作用,而不是为每个输入编写单独的代码。

如果你真的很幸运,你将来可以通过添加测试用例来添加回归测试和新功能测试,而无需编写任何新的测试代码。

答案 5 :(得分:0)

是的,您应该测试未调用_repository.SaveStuff。实际上你需要编写四个测试。

  1. 如果ModelState.IsValid = SaveStuff
  2. 如果Not ModelState.IsValid =不SaveStuff
  3. 如果ModelState.IsValid = return RedirectToAction
  4. 如果Not ModelState.IsValid = return View
  5. 如果您在问题中说明,您同时测试了SaveStuffRedirectAction,那么您将进行一次脆弱的测试。

    使用相同的equivelant代码来显示正在发生的事情:

    [HttpPost]
    public ActionResult Edit(MyViewModel viewModel)
    {
       if (ModelState.IsValid)
       {
           _myRepository.SaveStuff(viewModel.Property1, viewModel.Property2);
       }
    
       if (ModelState.IsValid)
       {
           return RedirectToAction("MyAction", "MyController");
       }
    
       return View("Edit", viewModel);
    }