【问题标题】:Should I test that methods are NOT called?我应该测试不调用方法吗?
【发布时间】:2012-01-24 12:05:10
【问题描述】:

假设我有这个代码:

[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)。现在我想为这个方法编写单元测试......

我测试调用了repository中的方法,当modelstate有效时返回了一个RedirectToRoute。我测试当modelstate无效时返回ViewResult。

我的问题是,我是否也应该编写一个测试,以确保在模型状态无效时调用存储库上的方法?这看起来不错测试必须确保我没有得到任何不需要的保存。但是我觉得如果我走这条路,测试事情不会发生,我必须编写的测试数量会增加很多......

【问题讨论】:

    标签: unit-testing language-agnostic tdd


    【解决方案1】:

    该方法有多少条路径?

    对它们都进行测试不是很有意义吗?如果模型状态无效,保存会不会出错?

    确保发生的事情的数量通常受到被测方法的上下文的限制;如果模型无效(我假设),则模型不会被保存,这一点很重要。

    【讨论】:

    • 如果模型状态无效,保存数据肯定会出错。 ASP.NET MVC 中的 ModelState.IsValid 包含输入验证的结果,因此如果为 false,则用户提供了无效输入。
    • @haagel 这是一个反问:)
    • 啊,误会了:P
    【解决方案2】:

    回答你的问题,是的。你绝对应该测试一个方法在不应该被调用的时候没有被调用。您绝对不希望您的应用程序保留无效数据。

    如果您将所有内容分解为单独的测试,测试的数量将会增加,这也是正确的。不过,您的测试可以有多个断言。当状态无效时,我会结合这两个断言。这样您就不用编写几乎相同的测试了。

    【讨论】:

    • 只是个人意见,有时单个测试中的多个断言可能会使您更难理解测试正在测试什么(测试名称)以及失败时失败的原因。
    • @ToniParviainen - 多个断言需要与单个条件相关。在这种情况下,当模型状态无效时应该发生两件事:1)不应该保存任何内容,2)应该返回适​​当的视图。绝对应该远离关于不同条件的多个断言。
    【解决方案3】:

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

    我的回答通常是肯定的,你应该这样做,但实际上测试什么是你的决定。你应该测试任何让你担心的东西。

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

    【讨论】:

      【解决方案4】:

      是的,但我测试它的方式是有两个测试用例,一个有效,一个无效,并且在运行每个用例时记录被测代码调用的保存顺序。

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

      我这样做的一般原因是,最好在可能的情况下为被测试代码以不同方式处理的每种情况使用不同的测试代码。如果您在相同的测试代码中运行不同的测试数据,那么当您编写测试代码时,您将在应用程序代码中弄乱相同的边缘情况的可能性较小。因此,我尝试以“输入此输入并检查输出和副作用是否符合预期”的形式使用通用代码对给定函数进行尽可能多的测试。希望您也可以通过这种方式减少测试代码,因为您系统地测试所有输入的所有副作用,而不是为每个输入编写单独的代码。

      如果你真的很幸运,将来你只需添加测试用例就可以添加回归测试和新功能测试,而根本不需要编写任何新的测试代码。

      【讨论】:

        【解决方案5】:

        您想测试所有代码路径。如果它真的永远不会发生,那么您甚至不需要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());
        }
        

        希望有帮助!

        布兰登

        【讨论】:

          【解决方案6】:

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

          1. 如果ModelState.IsValid = SaveStuff
          2. 如果Not ModelState.IsValid = 不要SaveStuff
          3. 如果ModelState.IsValid = return RedirectToAction
          4. 如果Not ModelState.IsValid = return View

          如果如您的问题中所述,您将 SaveStuffRedirectAction 一起测试,您将有一个脆弱的测试。

          显示正在发生的事情的相同等效代码:

          [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);
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-02-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-09-27
            相关资源
            最近更新 更多