嘲笑副作用

时间:2012-06-07 12:37:03

标签: c# unit-testing mocking moq

使用Moq,是否可以设置模拟属性以使其变异?

例如,给定:

public interface IService // To be mocked.
{
    bool IsConnected { get; }
}

是否可以设置IService的模拟以便以下传递?

var mockService = new Mock<IService>();

// Setup mockService so IsConnected mutates...?

bool before = mockService.Object.IsConnected;

bool after = mockService.Object.IsConnected;

Assert.AreNotEqual(before, after);

当然,这种设置不起作用:

mockService.SetupGet(service => service.IsConnected).Returns(false);
mockService.SetupGet(service => service.IsConnected).Returns(true);

这是我的理解,即Moq没有实现记录/回放模型。

这是一个更现实的例子:

public interface IService // To be mocked.
{
    bool IsConnected { get; }

    void Connect(); // Mutates IsConnected.
}

class Client // To be tested
{
    private readonly IService service;

    public Client(IService service)
    {
        this.service = service;
    }

    public bool DoWork()
    {
        if (!service.IsConnected)  // In test, IsConnected should return false.
        {
            service.Connect();
        }

        if (!service.IsConnected) // In test, IsConnected should return true.
        {
            return false;
        }

        // ... yada yada yada more code

        return true;
    }
}

我正在使用Moq 4.0.10827.0。

1 个答案:

答案 0 :(得分:3)

您可以将返回值设置为Func<bool>而不是布尔值。然后,您将编写该func,以便更改其结果。像......那样......

bool isConnected = false
var mockService = new Mock<IService>();
// Setup mockService so IsConnected mutates...?
mockService.Setup(s => s.Connect()).Callback(() => isConnected = true);
mockService.SetupGet(s => s.IsConnected).Returns(() => isConnected);

bool before = mockService.Object.IsConnected;

mockService.Object.Connect();

bool after = mockService.Object.IsConnected;

Assert.AreNotEqual(before, after);

但是,根据您的服务的复杂程度,您可能需要考虑制作一个FakeService并使用它而不是模拟。