有没有办法为接口编写测试,然后针对实现测试的所有类进行测试?

时间:2009-12-21 06:33:53

标签: c# unit-testing interface mstest

我已经检查了这个.. similar question但是我不相信答案......

我目前有一个只由一个类实现的接口,但这迟早会发生变化。我目前对接口进行了测试,开头的所有测试都以:

开头
IFoo foo = GetConcreteFoo()

其中GetConcreteFoo类似于

IFoo GetConcreteFoo()
{
   return new ConcreteFooA();
}

但是,当我获得更多Foo的实现时,是否有办法让所有测试运行在所有不同具体foos的列表中?

我想如果没办法,至少我可以将测试复制/粘贴到一个新文件中,并使用具体类的名称,并更改GetConcreteFoo的返回对象... (并将原始文件从(IFooTests更改为IConcreteFooATests)。

我不认为这种方法特别糟糕..但它不太优雅/聪明,因为它会针对所有具体实现运行相同的测试(文件)。

有没有办法让它做到这一点?

(我正在使用MSTests)

谢谢!

2 个答案:

答案 0 :(得分:3)

不确定MSTest,但我相信您可以使用parameterised tests在NUnit中执行此操作,例如:使用实现类进行参数化并使用Activator.CreateInstance实例化它。

然而,更深层次的问题是,你想要吗?您没有说出您的界面是什么样的,但拥有界面的通常原因是允许不同的实现。例如,如果您有一个带有Area属性的IShape接口,那么Circle,Square和RorschachBlot将以不同的方式实现。什么可以测试IShape.Area属性可靠地断言?因此,一般来说,您可以实际测试类和(具体)方法。

当然,如果你的界面意味着界面规范之外的语义保证(例如,Area总是大于0),那么你可以测试你所知道的所有实现。 (对于您在创建测试时不了解的实现,您必须依赖于带外通信这些额外需求,例如通过文档和信任实现者来遵守它们。当代码合同发布时,您将能够强制执行通过合同类更可靠地满足这些要求。)

答案 1 :(得分:2)

简短回答,是的,你可以。更长的答案是它取决于很多因素,如何在你的测试套件中。

基本上你可以这样做:

public void GenericIFooTest(IFoo testFoo) {
   // each of your tests against foo here...
   Assert.IsTrue(testFoo.DoesItsThing());
}

然后您可以手动生成测试:

public void TestConcreteAFoo() {
   IFoo aFoo = new ConcreteAFoo(param1, param2, param3);

   GenericIFooTest(aFoo);
}
public void TestConcreteBFoo() {
   IFoo bFoo = new ConcreteBFoo();

   GenericIFooTest(bFoo);
}

或者你可以使用反射来做到这一点。这假设你知道如何动态地实例化每个foo,如果它有一个最好的默认构造函数:

public void TestAllFoos() {
   foreach(string assembly in Directory.GetFiles(assemblyPath, "*.dll", SearchOptions.All) {
      Assembly currentAssembly = Assembly.LoadAssembly(assembly);

      foreach(Type internalTypes in currentAssembly.GetTypes()) {
         if (internalTypes.IsAssignableFrom(IFoo) && !(internalTypes is IFoo)) {
            IFoo fooType = AppActivator.CreateInstance(internalTypes);

            GenericIFooTest(fooType);
         }
      }
   }
}

最后一部分是从我上周写的一些代码的记忆来做同样的事情,它有点粗糙,但应该让你开始。你当然可以使用LINQ来简化它,我只是不知道我头脑中的语法。