【问题标题】:How can I avoid writing duplicate Unit Tests for classes that implement the same interface?如何避免为实现相同接口的类编写重复的单元测试?
【发布时间】:2011-05-08 04:19:27
【问题描述】:

我刚刚开始使用 Visual Studio 2010 进行单元测试。我想知道是否有一个工作流可以让我创建一系列应用于接口的测试,然后将这些接口测试应用于任何和所有实现接口的类。

比如说我有如下界面。

public interface IAnimal
{
   public string Name {get;}
   public string Speak();
}

我显然可以有许多实现这个接口的类。

public class Dog:IAnimal
{
  public string Name {get{return "Dog";}}
  public string Speak{return "BARK BARK";}
  public bool LickBalls();
}

public class Cat:IAnimal
{
  public string Name {get{return "Cat";}}
  public string Speak{return "MEOW MEOW";}
  public bool Scratch();
}

所以我想定义一系列适用于所有IAnimals的测试

   public TestAnimalName(IAnimal animal)
   {      
       Assert.IsFalse(string.IsNullorEmpty(animal.Name));
   }

   public TestAnimalSpeak(IAnimal animal)
   {      
       string sound = animal.Speak();
       Assert.IsFalse(string.IsNullOrEmpty(sound));
   }

然后我想定义一个主TestAnimal() 方法,可以用来测试任何IAnimal

TestAnimal(IAnimal animal)
{
    TestAnimalName(animal);
    TestAnimalSpeak(animal);
}

然后我可以在测试IAnimal 的具体类型时调用这个TestAnimal() 方法。

[TestMethod]
TestCat()
{
    Cat c = new Cat();
    TestAnimal(c);
}

[TestMethod]
TestDog()
{
    Dog c = new Dog();
    TestAnimal(c);
}

然而,当我尝试在 Visual Studio 中执行此操作时,被调用方法中的 Asserts 会被忽略。我尝试用下面的方法简化问题,发现即使它调用了一个应该导致失败的方法,它也通过了。

[TestMethod]
public void AssertInCalledMethod() //this will pass
{
    Assert.IsTrue(true);
    Blah();
}

public void Blah()
{
    Assert.IsTrue(false);
}

那么如何避免为所有实现相同接口的类编写大量重复测试呢?

【问题讨论】:

  • 哇,这是来自 VS 单元测试的破坏行为。如果您使用 NUnit,它将按您的预期工作。
  • 我想说你的问题不是编写测试,这些对我来说似乎是合理的方法。问题在于 VS 单元测试中的破坏行为。
  • 虽然我不知道答案,但“LickBalls”方法让我大笑。
  • 所以 就是为什么 Microsoft 软件以有一点漏洞着称。他们的单元测试都通过了,所以可以发货了,对吧?
  • 我对具体问题没有疑问,但我注意到我一直使用这种通用技术与 VS 单元测试和被调用方法中的断言通常工作正常。您的问题与构建问题或您未显示的问题有关。

标签: c# .net unit-testing visual-studio-2010


【解决方案1】:

Greg Young 的Hei Hei Grensesnitt 对这个问题采取了稍微不同的方法,我喜欢这种方法。你可以写一个接口规范:

[InterfaceSpecification] 
public class ICanAddTests : AppliesTo<ICanAdd>{ 

    [Test] 
    public void can_add_two_numbers() { 
          Assert.AreEqual(5, sut.Add(2,3)); 
    } 
}

... 框架会自动为它找到的所有实现接口的类执行测试。这是使用 NUnit,而不是 MSTest,但我认为这是一个相当聪明的想法,并且使工作流程非常简单。

【讨论】:

  • 如果我的 [某些] 类没有无参数构造函数怎么办?我找不到 GrensesnittObjectLocator 用法的示例。
【解决方案2】:

你的最终代码sn-p:

[TestMethod]
public void AssertInCalledMethod() //this will pass
{
    Assert.IsTrue(true);
    Blah();
}

public void Blah()
{
    Assert.IsTrue(false);
}

在我的电脑上失败了。有时,Visual Studio 可能会对旧 dll 感到困惑并运行旧版本的测试(或正在测试的库),如果您重命名测试方法,重命名是否会反映在测试运行器中?

附:我认为您使用TestAnimal(IAnimal animal) 的方法是理想的...

【讨论】:

  • 嗯,是的,我不知道之前发生了什么。现在我再次运行它并且 AssertInCalledMethod 返回失败,因为它应该。所以看起来我上面描述的过程是正确的答案?
  • 是的 - 只需创建对您想要使用的抽象有意义的任何实用方法。我这样做(例如)是为了断言两个列表相等(并很好地打印差异)
猜你喜欢
  • 2015-12-18
  • 2018-02-03
  • 1970-01-01
  • 2011-01-28
  • 2022-08-22
  • 2020-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多