代码之家  ›  专栏  ›  技术社区  ›  Francisco Noriega

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

  •  1
  • Francisco Noriega  · 技术社区  · 15 年前

    我已经检查过了…… similar question 但我不相信答案…

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

    IFoo foo = GetConcreteFoo()
    

    其中getconcretefoo类似于

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

    然而,当我得到更多的foo实现时,有没有一种方法可以让所有测试运行在一个包含所有不同具体foo的列表中?

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

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

    有办法做到这一点吗?

    (IM使用MSTESTS)

    谢谢!

    2 回复  |  直到 15 年前
        1
  •  3
  •   itowlson    15 年前

    对MSTEST不太确定,但我相信你可以在努尼特用 parameterised tests 例如,使用实现类参数化,并使用Activator.CreateInstance将其实例化。

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

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

        2
  •  2
  •   GrayWizardx    15 年前

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

    基本上你可以这样做:

    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来简化它,我只是不太清楚它的语法。