我对使用ServiceStack创建的一些服务类编写单元测试(使用NUnit)感兴趣,使用“New API”(继承自ServiceStack.ServiceInterface.Service)。当使用AppHost在ASP.NET应用程序中托管时,服务的Db属性是正确自动连接的,但是当在该环境之外运行时,我似乎无法弄清楚正确的技术。我在ServiceStack中看到了各种与测试相关的命名空间和类,但是找不到注入服务的Db属性的明确示例,而不是简单地直接设置连接工厂然后调用各种IDbConnection扩展方法(Insert ,选择等。)。
我试过让我的测试类继承自ServiceStack.ServiceInterface.Testing.TestBase并重写其Configure方法来注册IDbConnectionFactory(使用“:memory:”),以及在我的TestFixtureSetUp中设置OrmLiteConfig.DialectProvider = SqliteDialect.Provider;
,但是在调用我的服务方法时(在ServiceStack.ServiceInterface.Service.get_Db()处),我继续得到NullReferenceException。似乎Funq容器没有自动连接任何东西。
SQLite本身已经正确设置,我可以通过更简单的单元测试来确认,这些单元测试绕过我的服务类并且只是直接进行IDbConnection调用。
我错过了什么?
修改
单元测试ServiceStack服务似乎需要存在主机和客户端,尽管看起来有办法设置它以避免序列化成本(使用DirectServiceClient,如图here所示) - 虽然我没有成功地让我的工作在我的情况下。我设法使用AppHostHttpListenerBase方法(参见here)来实现这一点,尽管它更像是集成测试而不是单元测试(因此速度较慢)。
答案 0 :(得分:5)
docs on Testing显示了几种注入依赖关系的不同方法。
如果您查看基础Service的实现,它只会从IDbConnectionFactory
创建 Db :
private IDbConnection db;
public virtual IDbConnection Db
{
get { return db ?? (db = TryResolve<IDbConnectionFactory>().OpenDbConnection()); }
}
它只是从本地或全球IResolver
IOC容器解析:
public static IResolver GlobalResolver { get; set; }
private IResolver resolver;
public virtual IResolver GetResolver()
{
return resolver ?? GlobalResolver;
}
public virtual T TryResolve<T>()
{
return this.GetResolver() == null
? default(T)
: this.GetResolver().TryResolve<T>();
}
因此,要注入自己的依赖项(使用Service基类时),您只需要配置一个IAppHost
,其中包含您可以使用的服务所需的依赖项:
using (var appHost = new BasicAppHost {
ConfigureContainer = c => {
c.Register<IDbConnectionFactory>(new ...);
}
}.Init())
{
//...
}
然后,您可以根据自己的服务需要设置自己的服务,例如:
var service = appHost.ResolveService<MyService>();
哪个将自动装配AppHost中配置的所有依赖项,您还可以通过正常的属性访问添加自己的特定于测试的依赖项,例如:
var service.MyDependency = new Mock<IMyDependency>().Object;
从那时起,你可以按照惯例调用和测试你的C#类方法:
var response = service.Get(new RequestDto { ... });
Assert.That(response.Result, Is.Equal("Expected Result from DB"));