Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking side effects

With Moq, is it possible to setup a mocked property so that it mutates?

For example, given:

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

Is it possible to setup a mock of IService such that the following passes?

var mockService = new Mock<IService>();

// Setup mockService so IsConnected mutates...?

bool before = mockService.Object.IsConnected;

bool after = mockService.Object.IsConnected;

Assert.AreNotEqual(before, after);

Certainly this setup doesn’t do the trick:

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

That is consistent my understanding that Moq does not implement the record/playback model.

Here is a little more realistic example:

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;
    }
}

I’m using Moq 4.0.10827.0.

like image 989
Watsontap Avatar asked Jan 21 '26 23:01

Watsontap


1 Answers

You can set Returns to a Func<bool> instead of a bool. You would then have write that func such that it changes its result. Something like....

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);

However, depending on how complicated your serivce gets, you may want to consider making a FakeService and use that instead of mocking.

like image 90
cadrell0 Avatar answered Jan 23 '26 11:01

cadrell0



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!