C# 有没有一种方法可以为接口编写测试,然后针对实现该测试的所有类对其进行测试?

C# 有没有一种方法可以为接口编写测试,然后针对实现该测试的所有类对其进行测试?,c#,unit-testing,interface,mstest,C#,Unit Testing,Interface,Mstest,我已经查过了。。但我不相信答案 我目前有一个接口,它只由一个类实现,但迟早会改变的。我目前有一个针对接口的测试,开始时的所有测试都从以下内容开始: IFoo foo = GetConcreteFoo() GetFoo是什么样子的 IFoo GetConcreteFoo() { return new ConcreteFooA(); } 然而,当我得到更多的Foo实现时,是否有一种方法可以让所有测试都针对所有不同的具体Foo列表运行 我想如果没有办法,至少我可以用concreteclass

我已经查过了。。但我不相信答案

我目前有一个接口,它只由一个类实现,但迟早会改变的。我目前有一个针对接口的测试,开始时的所有测试都从以下内容开始:

IFoo foo = GetConcreteFoo()
GetFoo是什么样子的

IFoo GetConcreteFoo()
{
   return new ConcreteFooA();
}
然而,当我得到更多的Foo实现时,是否有一种方法可以让所有测试都针对所有不同的具体Foo列表运行

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

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

有没有办法做到这一点

(即时通讯使用MSTests)


谢谢!

不确定MSTest,但我相信您可以在NUnit中使用,例如,使用实现类参数化并使用Activator.CreateInstance实例化它

然而,更深层次的问题是,你想不想?你没有说你的接口看起来像什么,但是拥有一个接口的通常原因是允许不同的实现。例如,如果你有一个具有面积属性的IShape接口,那么它将通过圆、方和罗夏印记来实现。测试可以是什么因此,对于IShape.Area属性,通常只能测试类和(具体的)方法


当然,如果您的接口意味着接口规范之外的语义保证(例如,面积始终大于0),那么您可以对您所知道的所有实现进行测试。(对于创建测试时您不知道的实现,您必须依赖于在带外传达这些附加需求,例如通过文档,并信任实现者遵守这些需求。当代码契约发布时,您将能够通过契约类更可靠地实施这些需求。)不确定MSTest,但我相信您可以在NUnit中使用,例如,使用实现类参数化并使用Activator.CreateInstance实例化它

然而,更深层次的问题是,你想不想?你没有说你的接口看起来像什么,但是拥有一个接口的通常原因是允许不同的实现。例如,如果你有一个具有面积属性的IShape接口,那么它将通过圆、方和罗夏印记来实现。测试可以是什么因此,对于IShape.Area属性,通常只能测试类和(具体的)方法


当然,如果您的接口意味着接口规范之外的语义保证(例如,面积始终大于0),那么您可以对您所知道的所有实现进行测试。(对于创建测试时您不知道的实现,您必须依赖于在带外传达这些附加需求,例如通过文档,并信任实现者遵守这些需求。当代码契约发布时,您将能够通过契约类更可靠地实施这些需求。)简短的回答,是的,你可以。较长的回答是,它将取决于很多因素,比如它在你的测试套件中如何运行

基本上你可以这样做:

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来简化它,我只是不知道我头脑中的语法。

简短的回答,是的,你可以。较长的回答是,它将取决于很多因素,比如它在你的tes中如何运行t套房

基本上你可以这样做:

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来简化它,我只是不知道我头脑中的语法。

+1总的来说,这是一个很好的答案,但是作为回归测试,进行这种集成测试也很有价值另一件事是,如果你有一个暗示“语义保证超出接口规范”的接口它是抽象类而不是接口的主要候选对象。是的,接口确实意味着语义保证,因为它适用于存储库,在存储库中,独立于实现,getAll获取全部,Add添加新元素,Update将更新元素,等等。该方法应始终具有相同的可测试结果,独立于实现我应该让它成为一个抽象类吗?如果我这样做了,我仍然需要对所有的实现进行测试。虽然谈论参数化测试让我想到了PEX,但我也要检查一下。总体来说+1是一个好答案,但是做这种集成测试作为回归测试套件也是很有价值的。另一件事是,如果你有一个暗示“接口规范之外的语义保证”的接口它是抽象类而不是接口的主要候选。是的,接口确实暗示语义保证,因为它是一个存储库,在这个存储库中,独立于实现,getAll获取全部,Add添加新元素Update