【问题标题】:How do I test a Signal R hub that has LifetimeScope injected into it如何测试注入了 Lifetime Scope 的 Signalr 集线器
【发布时间】:2020-04-13 22:07:51
【问题描述】:

如何编写单元测试来测试我的集线器?

这是我的 Hub 类:

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() 没有定义

【问题讨论】:

    标签: signalr moq autofac xunit


    【解决方案1】:

    这可能不是您要寻找的答案。但是解决方法不是模拟生命周期,而是简单地设置一个 autofac 容器以在这些测试中使用。 其次,您是否需要直接在您的课程中注入生命周期范围?也许使用装饰器模式,让装饰器创建生命周期并解析您的类并调用它。摆脱 myhub 课程中的 lifescope 将使您的生活更轻松。让它成为其他类的工作来控制生命周期。否则,您还需要在所有其他课程中重复此模式。您应该改为注入 IMyProvider。

    【讨论】:

    【解决方案2】:

    这就是我解决这个问题的方法:

    如果我将中心更改为以下内容:

    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&lt;IMyProviider&gt; 以返回我需要的内容并忽略生命周期范围

    【讨论】:

    • 只要注入IMyProvider就更简单了。并摆脱了 Func 的东西
    • @ChristianJohansen 感谢您的评论。我遇到了一个问题,其中 MyProvider 是一个空引用——依赖链中的后续代码需要(不是我的调用)我们来管理我们支持的信号 r 对象的生命周期依赖关系,因此所有注入到集线器或链在我的注册中被标记为 .ExternallyOwned()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 2020-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多