【问题标题】:How best to unit test a ServiceStack service that uses IServiceGateway to call other internal services如何最好地对使用 IServiceGateway 调用其他内部服务的 ServiceStack 服务进行单元测试
【发布时间】:2020-08-15 09:11:02
【问题描述】:

我一直在遵循这里的指南 - https://docs.servicestack.net/testing

我正在尝试进行单元测试而不是集成,只是为了降低模拟级别和其他复杂性。

我的一些服务通过推荐的 IServiceGateway API 调用我的其他一些服务,例如Gateway.Send(MyRequest)。

但是在运行测试时我得到 System.NotImplementedException: 'Unable to resolve service 'GetMyContentRequest''。

我使用了处理这个请求的服务 container.RegisterAutoWired()。

我不确定下一步该去哪里。我真的不想重新开始设置集成测试模式。

【问题讨论】:

  • 你最终是如何解决这个问题的?我也有同样的挑战。如果我不使用网关,它可以正常工作,只需从调用方解析“其他服务”,但这似乎不是推荐的方式。

标签: unit-testing servicestack inversion-of-control


【解决方案1】:

如果您尝试将服务集成作为单元测试执行,而不是在经过验证的有效状态下启动的集成测试,您可能会不断遇到问题。

但是对于网关请求,它们是使用 IServiceGateway 执行的,您可以选择在自定义 AppHost 中使用自定义实现覆盖 implementing GetServiceGateway(),或者通过在中注册 IServiceGatewayFactory 或 IServiceGateway你的国际奥委会,这是默认实现:

public virtual IServiceGateway GetServiceGateway(IRequest req)
{
    if (req == null)
        throw new ArgumentNullException(nameof(req));

    var factory = Container.TryResolve<IServiceGatewayFactory>();
    return factory != null ? factory.GetServiceGateway(req) 
        : Container.TryResolve<IServiceGateway>()
        ?? new InProcessServiceGateway(req);
}

【讨论】:

  • 是的,我刚刚意识到这可能会导致电话持续呈螺旋式上升。
  • 没有更简单的方法吗?基于 AppHost 的集成测试很慢,所以我更喜欢基于 BasicAppHost 的“单元测试”。内部测试我会做var srv = container.Resolve&lt;MyService&gt;(); srv.Get(new MyDto(...))。 MyService 调用(内部)服务 OtherService。在测试中,OtherService 被 mocked 并添加到 BasicAppHost 的 容器中。在 MyService.Get(MyDto ..) 内部使用 Resolve&lt;OtherService&gt; 可以正常工作,但不推荐。 SS docs 推荐Gateway.Send,这不起作用(找不到服务)。
  • @specimen 如果您只是想测试您的服务,您可以从 IOC 解决它并直接调用该方法,但这不会测试任何 AppHost 集成,如果您的服务尝试将失败访问 IRequest 或 IResponse 否则应该没问题。但是我总是推荐集成测试,这是对真实环境的更好测试。如果速度较慢,则测试夹具较少但较大,因此每个夹具只需执行一次 AppHost 启动成本。
  • @specimen 如果你的服务使用服务网关,你需要在 IOC 中使用集成测试或模拟 IServiceGateway
  • 感谢您的耐心等待。我做错的是模拟服务,而我应该模拟网关。我已经花时间发布完整的答案,为后代。
【解决方案2】:

根据@mythz 的回答中的讨论,这是我的解决方案:

像OP这样的用例:测试“主”服务,并模拟“子服务”,就像OP一样,我想用单元测试(所以BasicAppHost)来做到这一点,因为它更快,我相信它是以这种方式更容易模拟服务(旁注:对于基于 AppHost 的集成测试,SS 将扫描程序集以查找(真实)服务,那么如何模拟?从“容器”中注销并替换 w.mock?)。

无论如何,对于单元测试:

我的“主要”服务正在使用另一个服务,通过 IServiceGateway(这是官方推荐的方式):

public MainDtoResponse Get(MainDto request) {
  // do some stuff
  var subResponse = Gateway.Send(new SubDto { /* params */ });
  // do some stuff with subResponse
}

在我的测试设置中:

appHost = new BasicAppHost().Init();

var mockGateway = new Mock<IServiceGateway>(); // using Moq
mockGateway.Setup(x => x.Send<SubDtoResponse>(It.IsAny<SubDto>()))
  .Returns(new SubDtoResponse { /* ... */ });
container.Register(mockGateway.Object);

所以必须mock IServiceGateway,然后Send方法才是重要的。我做错的是模拟服务,而我应该模拟网关。

然后以正常方式调用 主服务(正在测试中)进行单元测试,就像在文档中一样:

var s = appHost.Container.Resolve<MainService>(); // must be populated in DI manually earlier in code
s.Get(new MainDto { /* ... */ })

PS:mockGateway.Setup 可以在每个测试中使用,不一定在OneTimeSetUp中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 2013-10-17
    • 1970-01-01
    • 2012-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多