2009-12-21 90 views
1

我已经检查了这个.. similar question但我不确定答案...有没有办法为接口编写测试,然后对所有实现测试的类进行测试?

我目前有一个接口只能由一个类实现,但是迟早会发生变化。我现在有对接口的测试,并在一开始所有测试开始:

IFoo foo = GetConcreteFoo() 

其中GetConcreteFoo是一样的东西

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

,当我拿到美孚的多种实现,莫不是一种使所有测试运行在所有不同具体foos列表上的方法?

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

我不认为这种方法是特别坏..但它不是太优雅/高明,因为这将是在其上运行的所有具体实现相同的测试(文件)。

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

(Im使用MSTests)

谢谢!

回答

3

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

但是,更深层的问题是,你想吗?你没有说你的界面是什么样的,但是有一个界面的通常原因是允许不同的实现。例如,如果您有一个具有Area属性的IShape接口,那么Circle,Square和RorschachBlot将以不同方式实现。 IShape.Area属性的测试能够可靠地声明什么?因此,一般来说,您可以真实地测试类和(具体)方法。当然,如果你的界面是为了暗示界面规范之外的语义保证(例如Area总是大于0),那么你可以测试你知道的所有实现。 (对于您在创建测试时不知道的实现,您必须依靠通过文档传递这些额外的需求,并相信实现者遵守这些要求。当代码合同发布后,您将能够实施这些要求通过合同类更可靠。)

+0

+1总体而言,这是一个很好的答案,但做这样的集成测试也可以作为回归测试套件。另一件事是,如果你有一个接口暗示“接口规范之外的语义保证”,那么它就是抽象类而不是接口的主要候选者。 –

+0

是的界面确实意味着语义上的保证,因为它是一个独立于实现的存储库,getAll全部获取,Add添加一个新元素,Update更新一个元素等。该方法应该始终具有相同的可测试结果,独立于实施。 我应该让它成为一个抽象类吗?如果我这样做,我仍然需要测试所有的实现。 虽然谈论参数化测试让我思考PEX,但我也要检查一下。 –

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); 
} 

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

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

+0

你的建议是相当不错的选择,我会尝试他们和参数化的测试,看看我觉得最舒服:) –

+0

你可以将它们与参数化测试结合起来,也许使用参数来加载你所关心的组件或类型。 – GrayWizardx

相关问题