How to mock Autofaq interface with Moq

此生再无相见时 提交于 2020-04-11 08:33:08

问题


Using C#/Autofac/Moq: I have this class:

public class MyService
{
    private readonly IlifetimeScope _scope;

    public MyService(ILifetimeScope scope)
    {
        _scope = scope;
    }

    public void DoWork()
    {
         var dbContext = _scope.Resolve<IDataContext>();
    }
}

This works at runtime. However, I can't unit test it, since I cannot mock the Resolve() method. It is an extension method.

What's the best way to be able to mock it? The obvious thing would be to inject the IDataContext in the constructor instead of the ILifetimeScope, but for various reasons I cannot.

So, would it work to inject a Func instead?

public class MyService
{
    private readonly Func<IDataContext> _dbContext;

    public MyService(Func<IDataContext> dbContext)
    {
        _dbContext = dbContext;
    }

    public void DoWork()
    {
         var ctxt = _dbContext();
         // do stuff
    }
}

As in: I can mock it, but will Autofac figure out how to inject the correct parameter to the ctor? Or is there a better/simpler way to do this?


回答1:


I know doing this is not ideal, but in some more uncommon scenarios it may be necessary.

I had a situation that was a bit different. I have a method that needs to create a new context on demand, it is a console app so it's not like core's MVC that would begin a new lifetimescope per request. So I got the Autofac/Moq extension: http://autofac.readthedocs.io/en/latest/integration/moq.html

This will allow you to tell the container what instance to return for a particular interface.

Then you can pretty much do it like this:

[Fact]
public void Test()
{
    using (var mock = AutoMock.GetLoose())
    {
        var moqMockMe = new Mock<MockMe>();
        moqMockMe.Setup(s => s.AmIMocked()).Returns("Yes");
        mock.Provide(moqMockMe.Object);

        var lifeTimeScope = mock.Create<ILifetimeScope>();
        using (var scope = lifeTimeScope.BeginLifetimeScope())
        {
            var mockMeInsideScope = scope.Resolve<MockMe>();
            var actual = mockMeInsideScope.AmIMocked();
            Assert.Equal("Yes", actual);
        }
    }
}

public interface MockMe
{
    string AmIMocked();
}

public class MockMeImpl : MockMe
{
    public string AmIMocked()
    {
        return "No";
    }
}

So in case the service you're calling has a method that begins a new lifetimescope, you can mock the result and test it by using this fake ILifeTimeScope created in the example above.




回答2:


For anyone else looking at this; the Func<T> trick worked for me.




回答3:


Have you considered simply mocking the scope?

public class Test
{
    private readonly Mock<ILifetimeScope> _scopeMock;
    private readonly Mock<IDataContext> _contextMock;

    public Test()
    {
        _contextMock = new Mock<IDataContext>();
        _scopeMock = new Mock<ILifetimeScope>();
        _scopeMock.Setup( s => s.Resolve<IDataContext>() ).Returns( _contextMock.Object );
    }
}


来源:https://stackoverflow.com/questions/44143810/how-to-mock-autofaq-interface-with-moq

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!