有没有办法保护遵循MethodName_Condition_ExpectedBehaviour模式的单元测试名称以防止重构?

时间:2011-12-27 10:57:30

标签: c# unit-testing tdd resharper

我遵循

的命名惯例
  

MethodName_Condition_ExpectedBehaviour

在命名测试特定方法的单元测试时。

例如:

[TestMethod]
public void GetCity_TakesParidId_ReturnsParis(){...}

但是当我需要重命名测试方法时,像ReSharper这样的工具不能让我重命名那些测试。

有没有办法防止重命名后出现此类情况?比如更改ReSharper设置或遵循更好的单元测试命名约定等?

3 个答案:

答案 0 :(得分:7)

最近的模式是通过他们测试的方法将测试分组到内部类中。

例如(省略测试属性):

public CityGetterTests 
{
   public class GetCity
   {
      public void TakesParidId_ReturnsParis()
      {
          //...
      }

      // More GetCity tests
   }
}

有关详细信息,请参阅Structuring Unit Tests from Phil Haack's blog

这种布局的巧妙之处在于,当方法名称发生变化时, 你只需要更改内部类的名称而不是全部 个别测试。

答案 1 :(得分:1)

我也从这次转换开始,但结果却感觉不是很好。现在我使用像should_return_Paris_for_ParisID这样的BDD样式名称。

这使我的测试更具可读性,而且允许我重构方法名称而不用担心我的测试:)

答案 2 :(得分:0)

我认为这里的关键是应该进行测试。

你在标签中提到了TDD,所以我希望我们在这里努力坚持这一点。通过这种模式,你写的测试有两个目的:

  1. 支持您的代码一旦编写完成,您就可以重构,而不必担心您已经破坏了某些内容

  2. 指导我们更好地设计组件 - 首先编写测试真的会让您思考解决手头问题的必要条件。

  3. 我知道起初看起来这个问题是关于第一点,但我认为这是第二点。你遇到的问题是你已经测试了具体的组件,而不是合同。

    在代码方面,这意味着我认为我们应该测试接口而不是类方法,否则我们会将测试暴露给与测试组件而不是合同相关的各种问题 - 继承策略,对象构造,以及重命名。

    接口名称也会改变,但它们会比方法名称更加严格。 TDD给我们提供的不仅仅是通过测试工具支持变革的一种方式 - 它提供了洞察力,以实现我们可能以错误的方式进行变革!

    以您提供的代码块为例:

    [TestMethod]
    public void GetCity_TakesParidId_ReturnsParis(){...}
    {
        // some test logic here
    }
    

    让我们说我们在对象 CityObtainer 上测试方法 GetCity() - 我什么时候设置了这个对象?我为什么这样做?如果我意识到 GetMatchingCity()是一个更好的名字,那么你就会遇到上面列出的问题!

    我建议的解决方案是,我们通过使用接口来考虑这个方法在过程中对早期的真正含义:

    public interface ICityObtainer
    {
        public City GetMatchingCity();
    }
    

    通过以这种“从外到底”的方式写作,我们不得不在此过程中更早地考虑我们想要的对象,并且它成为焦点应该减少其波动性。这并没有消除你的问题,但它可能会有所缓解(而且,我认为,无论如何,这是一种更好的方法)。

    理想情况下,我们更进一步,在开始测试之前我们甚至不编写任何代码

    [TestMethod]
    public void GetCity_TakesParId_ReturnsParis
    {
        ICityObtainer cityObtainer = new CityObtainer();
        var result = cityObtainer.GetCity("paris");
    
        Assert.That(result.Name, Is.EqualTo("paris");
    }
    

    这样,在我开始编写之前,我可以从组件中看到我真正想要的 - 如果 GetCity()不是我想要的,但是而 GetCityByID(),在此过程中会很明显。正如我上面所说,它并非万无一失,但它可能会减轻这种特殊情况的痛苦。

    一旦你完成了这个,我觉得如果你改变方法的名称,那是因为你改变了合同的条款,这意味着你 必须返回并重新考虑测试(因为您可能不想更改它)。

    (作为一个快速的附录,如果我们正在考虑使用TDD进行测试,那么 GetCity()内部会发生一些有大量逻辑的事情。考虑测试作为合同有助于我们将意图与实施分开 - 无论我们在界面背后发生什么变化,测试都将保持有效!)