从测试类调用测试类的非默认构造函数

时间:2014-08-12 10:26:23

标签: c# unit-testing tdd nunit nsubstitute

我是单位测试的新手,我想知道这是怎么回事,我想这是典型的,问题通常会解决:
我有受保护的方法,我想测试。我用测试类覆盖了测试类,但测试类的构造函数有4个参数,没有默认构造函数。在测试类的哪一部分中添加对base(4 args)构造函数的调用?我尝试使用[SetUp]方法,但出现Use of keyword 'base' is not valid in this context错误。

我认为这个简单的案例是自我解释,但这是一个例子:

public class A
{
    protected Class1 obj1;
    protected Class2 obj2; 
    protected Class3 obj3; 
    protected Class4 obj4;

    public A(Class1 obj1, Class2 obj2, Class3 obj3, Class4 obj4)
    {
        this.obj1 = obj1;
        this.obj2 = obj2;
        this.obj3 = obj3;
        this.obj4 = obj4;
    }

    protected virtual void MethodA()
    {
        //some logic
    }
}

[TestFixture]
public class ATests : A
{
    [SetUp]
    public void SetUp()
    {            
        this.obj1 = Substitute.For<Class1>();
        this.obj2 = Substitute.For<Class2>();
        this.obj3 = Substitute.For<Class3>();
        this.obj4 = Substitute.For<Class4>();
        //this line below doesn't compile with the `Use of keyword 'base' is not valid in this context` error.
        base(obj1, obj2, obj3, obj4);
    }

    [Test]
    public void MethodA_test()
    {
        //test MethodA logic
    }
}

2 个答案:

答案 0 :(得分:1)

ATests不应该继承A

只需将测试类定义更改为

即可
[TestFixture]
public class ATests
{

然后代替

base(obj1, obj2, obj3, obj4);

做类似

的事情
this.globalA = new A(obj1, obj2, obj3, obj4);

其中globalAA类型的私有字段,您可以在测试中使用该字段。


要访问protected方法,您可以将测试项目作为friend assembly添加到主项目中,并将protected方法标记为protected internal

答案 1 :(得分:1)

通用且简单的方法是创建从A派生的类,它将公开您想要测试的受保护成员:

public class TestableA : A
{
    public void TestableMethodA() 
    {
        base.MethodA();
    }
}

现在,您的测试夹具将改为TestableA。您实际上并非从A派生测试夹具,只需在测试中使用新派生的仅测试类:

[TestFixture]
public void ATests
{
    [Test]
    public void MethodA_DoesSomethingImportant()
    {
        var testedComponent = new TestableA();
        testedComponent.TestableMethodA();
        // verify 
    }
}

这种方法的缺点是需要创建额外的类型以仅用于测试目的。这可以通过模拟框架使用(以及使用模拟调用基础实现)来缓解。更改方法可见性纯粹用于单元测试的目的应该是其他一切失败或最终成本高昂的最后手段。