Unit testing 如何对接口进行单元测试?

Unit testing 如何对接口进行单元测试?,unit-testing,interface,tdd,Unit Testing,Interface,Tdd,例如,有一个接口IMyInterface,有三个类支持此接口: class A : IMyInterface { } class B : IMyInterface { } class C : IMyInterface { } 以最简单的方式,我可以编写三个测试类:ATest、BTest、CTest并分别测试它们。然而,由于它们支持相同的接口,大多数测试代码都是相同的,很难维护。如何使用简单易用的方法测试不同类支持的接口 ()可以创建采用IMyInterface类型参数的方法,并让实际的测试

例如,有一个接口
IMyInterface
,有三个类支持此接口:

class A : IMyInterface
{
}

class B : IMyInterface
{
}

class C : IMyInterface
{
}
以最简单的方式,我可以编写三个测试类:ATest、BTest、CTest并分别测试它们。然而,由于它们支持相同的接口,大多数测试代码都是相同的,很难维护。如何使用简单易用的方法测试不同类支持的接口


()

可以创建采用IMyInterface类型参数的方法,并让实际的测试方法只调用传入不同具体类的方法。

您不直接测试接口,但可以编写一个抽象类来测试特定实现应扩展的契约。具体类的测试随后将扩展抽象类,以使用公共测试测试接口,而不管实现如何,您都可以使用抽象测试用例,然后为接口的每个实现创建测试用例的具体实例


抽象(基本)测试用例执行与实现无关的测试(即验证接口契约),而具体测试负责实例化要测试的对象,并执行任何特定于实现的测试。

如果要以NUnit为例,对接口的不同实现者运行相同的测试:

public interface IMyInterface {}
class A : IMyInterface { }
class B : IMyInterface { }
class C : IMyInterface { }

public abstract class BaseTest
{
    protected abstract IMyInterface CreateInstance();

    [Test]
    public void Test1()
    {
        IMyInterface instance = CreateInstance();
        //Do some testing on the instance...
    }

    //And some more tests.
}

[TestFixture]
public class ClassATests : BaseTest
{
    protected override IMyInterface CreateInstance()
    {
        return new A();
    }

    [Test]
    public void TestCaseJustForA()
    {
        IMyInterface instance = CreateInstance();   
        //Do some testing on the instance...
    }

}

[TestFixture]
public class ClassBTests : BaseTest
{
    protected override IMyInterface CreateInstance()
    {
        return new B();
    }
}

[TestFixture]
public class ClassCTests : BaseTest
{
    protected override IMyInterface CreateInstance()
    {
        return new C();
    }
}

如果您使用的是NUnit,那么您可以使用Grensesnitt:

public interface ICanAdd {
    int Add(int i, int j); //dont ask me why you want different adders
}

public class winefoo : ICanAdd {
    public int Add(int i, int j)
    {
        return i + j;
    }
}

interface winebar : ICanAdd {
    void FooBar() ; 
}

public class Adder1 : winebar {
    public int Add(int i, int j) {
        return i + j;
    } 
    public void FooBar() {}
}

public class Adder2 : ICanAdd {
    public int Add(int i, int j) {
        return (i + 12) + (j - 12 ); //yeeeeeaaaah
    } 
}

[InterfaceSpecification]
public class WithOtherPlugins : AppliesToAll<ICanAdd>
{ 
    [TestCase(1, 2, 3)] 
    [TestCase(-1, 2, 1)]
    [TestCase(0, 0, 0)]
    public void CanAddOrSomething(int x, int y, int r)
    {
        Assert.AreEqual(subject.Add(x, y), r);
    }

    [TestCase(1, 2, Result = 3)]
    [TestCase(-1, 2, Result = 1)]
    [TestCase(0, 0, Result = 0)]
    public int CannAddOrSomethingWithReturn(int x, int y) {
        return subject.Add(x, y);
    }
}
公共接口添加{
int-Add(int-i,int-j);//不要问我为什么需要不同的加法器
}
公共类winefoo:ICanAdd{
公共整数相加(整数i,整数j)
{
返回i+j;
}
}
界面winebar:ICanAdd{
void FooBar();
}
公共类加法器1:winebar{
公共整数相加(整数i,整数j){
返回i+j;
} 
公共void FooBar(){}
}
公共类Adder2:ICanAdd{
公共整数相加(整数i,整数j){
返回(i+12)+(j-12);//YeeeeAaah
} 
}
[接口规范]
带有其他插件的公共类:AppliesToAll
{ 
[测试用例(1,2,3)]
[测试用例(-1,2,1)]
[测试用例(0,0,0)]
公共无效信息(整数x,整数y,整数r)
{
断言相等(主语加(x,y),r);
}
[测试用例(1,2,结果=3)]
[测试用例(-1,2,结果=1)]
[测试用例(0,0,结果=0)]
public int CannAddOrSomethingWithReturn(int x,int y){
返回主题。添加(x,y);
}
}

+1回答得不错!现在,NUnit支持通用测试类,并且可以使用TestFixture属性提供测试运行时要使用的特定类型。我写了一篇关于如何测试展示这些特性的接口的每个实现者的文章。我对单元测试还不熟悉,几天前我接受了你的建议,但是至少对于PHPUnit来说,我发现这相当困难-因为抽象类不能引用扩展类,所以没有办法真正编写抽象测试方法