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

时间:2010-06-25 22:27:29

标签: unit-testing interface tdd

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

class A : IMyInterface
{
}

class B : IMyInterface
{
}

class C : IMyInterface
{
}

用最简单的方法,我可以编写三个测试类:ATest,BTest,CTest并分别测试它们。但是,由于它们支持相同的接口,因此大多数测试代码都是相同的,很难维护。 如何使用简单易用的方法测试不同类支持的界面?

previously asked on the MSDN forums

5 个答案:

答案 0 :(得分:41)

如果您想使用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();
    }
}

答案 1 :(得分:19)

要测试具有常见测试的接口而不管实现如何,您可以使用抽象测试用例,然后为接口的每个实现创建测试用例的具体实例。

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

答案 2 :(得分:3)

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

答案 3 :(得分:2)

您不直接测试接口,但您可以编写一个抽象类来测试特定实现应该扩展的合同。然后,对具体类的测试将扩展抽象类

答案 4 :(得分:0)

如果您正在使用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);
    }
}