【发布时间】:2017-01-26 09:09:08
【问题描述】:
我最近完成了一个 .Net 项目,该项目通过 ServiceStack(3.9.71) REST API 从 Microsoft SQL 数据库公开 DAO。因为我要重构一些部分,所以我想对(至少)所有的 servicestack 服务进行单元测试。为了更好地理解,我快速草拟了实现的工作原理。
每个服务都包含一个DBService 类型的属性,它封装了所有 服务的所有 数据库访问。不幸的是,这是一个很难模拟的具体类。 DI.Container 包装了 ServiceStack 的 IOC。
public class SomeService : Service
{
public DBService { get { return DI.Container.Resolve<DBService>(); } }
public object Get(SomeDataClass class)
{
var response = DBService.SomeServiceGet();
return response;
}
// other code omitted
}
DBService 看起来像这样(草稿):
public class DBService
{
public IDbConnectionFactory DBFactory { get { return DI.Container.Resolve<IDbConnectionFactory>(); } }
public SomeServiceResponse SomeServiceGet()
{
//DB Access here...
// ...
}
public SomeOtherServiceResponse SomeOtherServiceGet()
{
//...
}
// following about 30 other methods for all the services (POST,GET,PUT etc)
}
我阅读了对此question 的详细回复,但我无法在ServiceStack 3.9.71 中创建和初始化BasicAppHost,因为它立即抛出了System.TypeLoadExceptionMethod 'get_VirtualPathProvider'。
另一方面,我认为我实际上并不需要BasicAppHost。我只需要对DBService 进行单元测试,然后使用某种模拟的DBService 对servicestack 服务进行单元测试。我唯一的问题是DBService 不是一个接口,实际上我不确定如何处理(模拟)SQL 数据库和IOC。
[更新]
不幸的是,我仍然无法测试服务,因为我不能只 new 测试中的服务。如果我这样做,我会得到:
System.TypeLoadException 无法从程序集中加载类型“ServiceStack.ServiceHost.IService”
这是我的测试:
[Fact]
public void SomeDataTest()
{
var serviceUnderTest = new SomeService();
var response = serviceUnderTest.Get(new SomeDataClass());
Assert.NotNull(response);
}
我想问题是服务强烈使用了很多通过 IOC 注入的属性。我怎么能嘲笑它?创建BasicAppHost 并从那里检索服务也不起作用,我已经提到过。
【问题讨论】:
-
一旦有问题的类都没有被密封,那么您可以创建自己的类来继承它们并覆盖或更新测试所需的行为。这很难模拟,但并非不可能。
-
所以我其实不用关心
IDbConnectionFactory的IOC注入?我也想知道它是否是一种更好的方法,所以为DBService实现一个接口,这样我就可以轻松地模拟它。 -
是的,抽象 DbService 将大大提高可测试性,您应该考虑将构造函数注入与您正在使用的 Service Locator 反模式相对应
-
显示失败的单元测试。以及任何相关类作为minimal reproducible example,可用于重现问题以找到解决方案。
标签: c# unit-testing servicestack moq xunit