Jimmie Andersson
Jimmie Andersson

Reputation: 447

Autofac mock - How do I setup/fake data from specific methods in dependencies?

I'm new to both unit tests, Autofac and mocks so likely, this is relatively easy, but I'm having a hard time figure it out.

I have this class SystemUnderTest with one dependency, and two methods GetValueOne and GetValueTwo.

public class SystemUnderTest : ISystemUnderTest
{
    private readonly IDependency _dependency;

    public SystemUnderTest(IDependency dependency)
    {
        _dependency = dependency;
    }

    public string GetValueOne()
    {
        return _dependency.GetValueOne();
    }

    public string GetValueTwo()
    {
        return _dependency.GetValueTwo();
    }
}

public interface ISystemUnderTest
{
    string GetValueOne();
    string GetValueTwo();
}

These methods gets data from the dependency.

public class Dependency : IDependency
{
    public string GetValueOne()
    {
        return "get-value-one";
    }
    public string GetValueTwo()
    {
        return "get-value-two";
    }
}

public interface IDependency
{
    string GetValueOne();
    string GetValueTwo();
}

I'm trying to fake the data from one of the methods (the "GetValueTwo") so its returning "expected value" instead of "get-value-two" which is what the dependency normally returns.

[Fact]
public async Task Test_SystemUnderTest()
{
    using (var mock = AutoMock.GetLoose())
    {
        // Setup
        mock.Mock<IDependency>().Setup(x => x.GetValueTwo()).Returns("expected value");

        // Configure
        mock.Provide<IDependency, Dependency>();

        // Arrange - configure the mock
        var sut = mock.Create<SystemUnderTest>();

        // Act
        var actual_GetValueOne = sut.GetValueOne();
        var actual_GetValueTwo = sut.GetValueTwo();

        // Assert - assert on the mock
        Assert.Equal("get-value-one", actual_GetValueOne);
        Assert.Equal("expected value", actual_GetValueTwo);
    }
}

The first part in my test, the Setup piece, does not seem to have any effect, and its probably because I'm doing some basic stuff wrong.

Anyone with insights on how to save my day?

Upvotes: 1

Views: 2072

Answers (2)

Nkosi
Nkosi

Reputation: 247018

The members of Dependency implementation would need to have virtual members for them to be able to be overridden when doing a partial mocked.

public class Dependency : IDependency {
    public virtual string GetValueOne() {
        return "get-value-one";
    }
    public virtual string GetValueTwo() {
        return "get-value-two";
    }
}

Then similar to what was suggested in another answer you would instead mock the implementation, making sure to enable it to call base members and only setup the members you need to override.

public void Test_SystemUnderTest() {
    using (var mock = AutoMock.GetLoose()) {
        // Setup
        var dependency = mock.Mock<Dependency>();
        dependency.CallBase = true;
        dependency.Setup(x => x.GetValueTwo()).Returns("expected value");

        // Configure
        mock.Provide<IDependency>(dependency.Object);

        // Arrange - configure the mock
        var sut = mock.Create<SystemUnderTest>();

        // Act
        var actual_GetValueOne = sut.GetValueOne();
        var actual_GetValueTwo = sut.GetValueTwo();

        // Assert - assert on the mock
        Assert.AreEqual("get-value-one", actual_GetValueOne);
        Assert.AreEqual("expected value", actual_GetValueTwo);
    }
}

The above passes when exercised provided that the members of the implementation that need to be mocked can be overridden (ie virtual).

Upvotes: 2

Dejan Janjušević
Dejan Janjušević

Reputation: 3230

Not an expert in writing unit tests, but I'm pretty sure that by using Provide with two type arguments, you overwrite the Setup part you did previously. By my understanding, the Provide method should be used to provide your own mock implementation of target interface, so using both Provide with two type arguments and Setup for the same dependency doesn't make sense.

So you can either modify the Dependency implementation's GetValueTwo to return "expected value" and use the rest of your code unmodified, or you can supply the mocked instance to the Provide method with one type argument, with both of the methods previously setup, like this:

    [Fact]
    public async Task Test_SystemUnderTest()
    {
        using (var mock = AutoMock.GetLoose())
        {
            var mockedDependency = mock.Mock<IDependency>();

            // Setup
            mockedDependency.Setup(x => x.GetValueOne()).Returns("get-value-one");
            mockedDependency.Setup(x => x.GetValueTwo()).Returns("expected value");

            // The following line is not even necessary
            mock.Provide<IDependency>(mockedDependency.Object);

            // Arrange - configure the mock
            var sut = mock.Create<SystemUnderTest>();

            // Act
            var actual_GetValueOne = sut.GetValueOne();
            var actual_GetValueTwo = sut.GetValueTwo();

            // Assert - assert on the mock
            Assert.Equal("get-value-one", actual_GetValueOne);
            Assert.Equal("expected value", actual_GetValueTwo);
        }
    }

Upvotes: 1

Related Questions