如何编写单元测试来测试我的集线器?
这是我的中心班级:
public class MyHub : Hub
{
private readonly ILifetimeScope _scope;
private readonly IMyProvider _provider;
public MyHub(ILifetimeScope scope)
{
scope = _scope;
_provider = _scope.Resolve<IMyProvider>();
}
public void BroadcastMessage(int messageId)
{
var myMessage = _provider.GetFromDb(messageId);
Clients.All.broadcastMessage(myMessage);
}
}
我正在使用moq和xunit,我已经尝试过类似的事情:
//arrange
var messageId = 1;
var message = "test";
var providerMock = new Mock<IMyProvider>();
providerMock.Setup(x => x.GetFromDb(messageId).Returns(test);
var scopeMock = new Mock<ILifetimeScope>();
scopeMock.Setup(x => x.Resolve<IMyProvider>()).Returns(providerMock.Object);
var hub = new MyHub(scopeMock.Object);
//act
hub.BroadcastMessage(messageId);
//assert
providerMock.Verify(x => x.GetFromDb(messageId), Times.Once());
但是这会导致错误:
System.NotSupportedException:不支持的表达式:x => x.Resolve()扩展方法(此处为:ResolutionExtensions.Resolve)不能在设置/验证表达式中使用。
我找到了这个答案:https://stackoverflow.com/a/49523868/3708225说我可以做类似的事情
using (var mock = AutoMock.GetLoose()){
var providerMock = new Mock<IMyPRovider>();
providerMock.Setup(x=>x.GetFromDb(messageId)).Returns(message);
mock.Provide(providerMock.Object);
var lifetime = mock.Create<ILifetimeScope>();
using (var scope = lifetimeScope.BeginLifetimeScope()){
var innerMockProvider = scope.Resolve<IMyProvider>();
//rest of test
}
}
但是AutoMock.GetLoose().Provide()
未定义
这可能不是您要寻找的答案。但是一种解决方法不是模拟生命周期范围,而是简单地设置一个autofac容器以在这些测试中使用。其次,您是否需要直接在您的班级中注入lifetimescope?也许使用装饰器模式,您可以让装饰器创建Lifetimescope并解析您的类并调用它。摆脱myhub类中的lifelifescope会使您的生活更轻松。使其他类的工作来控制Lifetimescope。否则,您将需要在所有其他类中重复此模式。您应该注入IMyProvider。
这是我解决这个问题的方式:
如果我将集线器更改为以下内容:
public class MyHub : Hub
{
private readonly <Func>IMyProvider _provider;
public MyHub(<Func>IMyProvider provider)
{
_provider = provider;
}
public void BroadcastMessage(int messageId)
{
var provider = _provider();
var myMessage = provider.GetFromDb(messageId);
Clients.All.broadcastMessage(myMessage);
}
}
现在我可以模拟Func<IMyProviider>
以返回我需要的内容,而忽略生命周期范围