在单元测试中跳过内部方法调用

时间:2016-04-04 08:16:19

标签: c# unit-testing xunit

让我们说,我有方法A,B,C和D.

public bool A (int foo)
{
    bool result = false;
    if (foo > 0)
        result = B();
    else result = C();
    D(foo);
    return result;
}

我想为A编写单元测试,调用B或C,但想跳过D调用(因为它是使用外部服务的方法)。是否可以使用某些属性跳过D调用?或者嘲笑D,用一些虚假服务代替它?

3 个答案:

答案 0 :(得分:2)

您需要使方法A()的类依赖于方法D()使用的外部服务。你可以使用任何DI模式来做到这一点,虽然构造函数注入可能是最好的起点。

一旦你处于这种情况,外部服务D()依赖于可以伪造并注入课堂。现在,您可以通过假冒行为来控制测试。

类似的东西:

class Thing
{
    private IExternalService _externalService;

    public Thing(IExternalService externalService)
    {
        _externalService = externalService;
    }

    public void A() { ... }

    public void D(string foo) 
    { 
        _externalService.DoSomeStuff();
    }
}

然后:

[Fact]
public void TestThisOut()
{
   var fakeExternalService = new MockFramework.CreateMock();
   fakeExternalService
       .ShouldDoSomethingWhen(s => s.DoSomeStuff())
       .IsCalled();

   var testThing = new Thing(fakeExternalService);

   testThing.A();

   Assert.That(testThing, Did.Some.Thing());
}

答案 1 :(得分:1)

这突出了设计代码的重要性,因此它可以进行单元测试。在这方面,依赖注入非常有用。然后,您可以在单元测试时模拟依赖项。例如,您可以通过接口ICommunications访问通信层。然后,您的类将在其构造函数中引用ICommunications对象:

public class TestableClass
{
    private ICommunications _comms;
    public TestableClass(ICommunications comms)
    {
        _comms = comms;
    }

    public bool FunctionToTest()
    {
        //do something testable

        _comms.SomeFunction();//mocked object in unit tests

        //do something else testable
    }
}

然后只需创建一个模拟版本的通信并在测试期间传递它。您还可以向模拟类添加代码以模拟某些测试条件 - 例如,对于接收一些无效数据的通信层。

答案 2 :(得分:0)

你需要模拟方法D.我写了一个例子,使用Typemock Isolator,看看:

class Methods
{
    public bool A(int foo)
    {
        bool result = false;
        if (foo > 0)
            result = B();
        else 
            result = C();
        D(foo);
        return result;
    }

    public void D(int foo) {throw new NotImplementedException();}

    public bool C() { return false;}

    public bool B() { return true;}
}

测试:

[TestMethod, Isolated]
public void TestIgnoreD()
{
    //Arrange
    Methods methods = new Methods();
    Isolate.WhenCalled(() => methods.D(0)).IgnoreCall();

    //Act
    bool result = methods.A(1);

    //Assert
    Assert.IsTrue(result);
}

我把它们全部放在一个班级中只是因为我不知道你的代码中发生了什么。无论如何,Isolator相当灵活,因为它几乎可以在任何地方模拟几乎所有东西。