【问题标题】:Approach on mocking ServiceStack service being called by another ServiceStack service模拟 ServiceStack 服务被另一个 ServiceStack 服务调用的方法
【发布时间】:2014-04-26 21:16:09
【问题描述】:

假设我们有一个服务会调用 ServiceStack 中的其他服务的情况。

通过阅读,这是调用另一个服务的方式:

public class CompanyService : Service
{
    public SetupCompanyResponse Any(SetupCompany request)
    {
        var employeeService = base.ResolveService<EmployeeService>();

        // Do something with employeeService
        var response = employeeService.Any(new SetupEmployees());

        return new SetupCompanyResponse { NumOfEmployeesCreated = response.Count };
    }
}

问题:如果我在对 CompanyService 进行单元测试,如何模拟 EmployeeService?

我能想到的最简单的方法是生成一个 IEmployeeService 接口,以便它易于模拟。但是我不确定base.ResolveService&lt;T&gt; 是否能够正确解析和自动连接 ServiceStack 服务,给定它的接口,如下所示:

var employeeService = base.ResolveService<IEmployeeService>();

特别是当我们以这种方式注册服务时(我假设是基于具体类而不是接口配置对象解析,例如IEmployeeService

public HelloAppHost() : base("Hello Web Services", typeof(HelloService).Assembly) { }

更新:

显然我可以通过以下方式在某种程度上实现这一目标:

1) 注册服务接口及其实现

public static void SetupServices(Container container)
{
    container.RegisterAs<EmployeeService, IEmployeeService>();
}

2) 使用相同的确切代码进行解析,除了现在我传入接口。服务已成功解析。

var employeeService = base.ResolveService<IEmployeeService>();

3) 我现在需要做的就是覆盖解析器,并且服务依赖项应该是完全可模拟的。

问题:这也是一种有效的方法吗?为什么或为什么不?

【问题讨论】:

    标签: servicestack


    【解决方案1】:

    ServiceStack 的 Service classIResolver 中解析其所有依赖项,定义为:

    public interface IResolver
    {
        T TryResolve<T>();
    }
    

    这可以通过多种方式注入到 ServiceStack 的 Service 类中,正如实现所见:

    public class Service : IService, IServiceBase, IDisposable
    {
        public static IResolver GlobalResolver { get; set; }
    
        private IResolver resolver;
        public virtual IResolver GetResolver()
        {
            return resolver ?? GlobalResolver;
        }
    
        public virtual Service SetResolver(IResolver resolver)
        {
            this.resolver = resolver;
            return this;
        }
    
        public virtual T TryResolve<T>()
        {
            return this.GetResolver() == null
                ? default(T)
                : this.GetResolver().TryResolve<T>();
        }
        ...
    }
    

    您可以使用它来控制服务如何解决依赖关系。

    对服务进行单元测试的一种简单方法是使用BasicAppHost,如Testing wiki 所示,即:

    appHost = new BasicAppHost().Init();
    var container = appHost.Container;
    
    container.Register<IDbConnectionFactory>(
        new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider));
    
    container.RegisterAutoWired<CompanyService>();
    container.RegisterAutoWiredAs<StubEmployeeService, EmployeeService>();
    

    StubEmployeeService 是您的 EmployeeService 的存根实现,例如:

    public class StubEmployeeService : EmployeeService 
    {
        public SetupEmployeesResponse Any(SetupEmployees request)
        {
            return new SetupEmployeesResponse  { ... };
        }
    }
    

    如果您更喜欢使用自己的模拟库,也可以使用任何注册方法ServiceStack's IOC Supports 注册服务。

    【讨论】:

    • 更新了显示新方法的问题。显然我只需要重新注册服务及其接口,默认解析器能够解析具体的服务,给定接口。
    猜你喜欢
    • 2016-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多