[英]How to mock Autofaq interface with Moq
使用 C#/Autofac/Moq:我有这个类:
public class MyService
{
private readonly IlifetimeScope _scope;
public MyService(ILifetimeScope scope)
{
_scope = scope;
}
public void DoWork()
{
var dbContext = _scope.Resolve<IDataContext>();
}
}
这在运行时有效。 但是,我无法对其进行单元测试,因为我无法模拟 Resolve() 方法。 它是一种扩展方法。
能够模拟它的最佳方法是什么? 显而易见的事情是在构造函数中注入 IDataContext 而不是 ILifetimeScope,但由于各种原因我不能。
那么,它可以代替注入 Func 吗?
public class MyService
{
private readonly Func<IDataContext> _dbContext;
public MyService(Func<IDataContext> dbContext)
{
_dbContext = dbContext;
}
public void DoWork()
{
var ctxt = _dbContext();
// do stuff
}
}
如:我可以模拟它,但是 Autofac 会弄清楚如何将正确的参数注入到 ctor 中吗? 或者有没有更好/更简单的方法来做到这一点?
我知道这样做并不理想,但在一些更不常见的情况下可能有必要。
我的情况有点不同。 我有一个方法需要根据需要创建一个新的上下文,它是一个控制台应用程序,所以它不像核心的 MVC 那样会为每个请求开始一个新的生命周期范围。 所以我得到了 Autofac/Moq 扩展: http ://autofac.readthedocs.io/en/latest/integration/moq.html
这将允许您告诉容器为特定接口返回什么实例。
然后你几乎可以这样做:
[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";
}
}
因此,如果您正在调用的服务有一个开始新生命周期范围的方法,您可以模拟结果并使用在上面的示例中创建的这个假 ILifeTimeScope 来测试它。
这远非理想,但可以检查扩展方法的内部结构并模拟它所做的实际非扩展调用。 显然,这很脆弱,因为新版本的 autofac 可能会破坏您的测试。
对我来说,以下是成功的(autofac v4.X):
Mock<IComponentRegistry> componentRegistryMock = new Mock<IComponentRegistry>(); IComponentRegistry componentRegistry = componentRegistryMock.Object; IComponentRegistration componentRegistration = new Mock<IComponentRegistration>().Object;
componentRegistryMock .Setup(x => x.TryGetRegistration(It.IsAny<Service>(), out componentRegistration)) .Returns(true); lifetimeScopeMock .Setup(x => x.ComponentRegistry) .Returns(componentRegistry);
componentRegistryMock .Setup(x => x.TryGetRegistration(It.IsAny<Service>(), out componentRegistration)) .Returns(true); lifetimeScopeMock .Setup(x => x.ComponentRegistry) .Returns(componentRegistry);
lifetimeScopeMock .Setup(x => x.ResolveComponent(componentRegistration, It.IsAny<IEnumerable>())) .Returns(dataService);
这对我有用:
var mock = AutoMock.GetLoose(builder => {
var dbContext = new Mock<IDataContext>();
dbContext.Setup(d => d.Something())
.Returns(whatever...);
builder.RegisterInstance(dbContext.Object).As<IDataContext>();
});
var myService = mock.Container.Resolve<MyService>();
对于其他正在看这个的人; Func<T>
技巧对我Func<T>
。
你有没有考虑过简单地嘲笑范围?
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 );
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.