如何对使用 Servicestack Funq IOC 的 DBService 进行单元测试
How to unit test DBService which uses the Servicestack Funq IOC
我是一个我应该扩展的项目的新手,所以我决定使用 TDD 来快速识别我不完全理解的系统的任何问题。
有一个 class 叫做 DBService
,它 "encapsulates" 所有数据库访问。例如,有一种方法称为 getAllCustomers
,其中 returns 是 Customers
的列表。这看起来像这样(这只是一个更好理解的例子):
public class DBService
{
public IDbConnectionFactory DBFactory {
get { return DI.Container.Resolve<IDbConnectionFactory>(); }
}
public List<Customer> GetAllCustomers()
{
try
{
using (var connection = DBFactory.OpenDbConnection())
{
var dbResult = connection.Select<Customer>();
// code ommitted
}
}
catch (Exception e)
{
// code ommitted
}
}
}
另一个问题是,在开始时(在 ServiceStack AppHost.Configure
中),如果所有表不存在,都会创建所有表,并且对于某些表,如果它们存在,则会添加一些列等(这可能是更改稍后添加)
例如,当我现在必须扩展客户并添加另一个字段时,我想以 TDD 样式添加地址,但我不知道如何做。
- 我无法注入任何
DBFactory
因为 getter 是私有的
- Afaik 我不能为
OrmLiteConnectionFactory
使用 :memory:
连接字符串,因为我使用的是 ServiceStack 3.9.74
那么我的选择是什么?
避免使用服务定位器anti-pattern,改用构造函数注入。尽量避免直接在依赖 classes 中使用 DI 容器。它将您的 classes 与不属于那里的问题紧密耦合,并且很难单独测试 classes。
public class DBService {
private readonly IDbConnectionFactory connectionFactory;
public DBService(IDbConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public IDbConnectionFactory DBFactory { get { return connectionFactory; } }
public List<Customer> GetAllCustomers() {
try {
using (var connection = DBFactory.OpenDbConnection()) {
var dbResult = connection.Select<Customer>();
//... code omitted for brevity
}
} catch (Exception e) {
//... code omitted for brevity
}
}
}
Select<T>
和 OpenDbConnection
看起来都像是扩展方法。我建议检查他们的期望值并模拟这些行为。
如果 DbService
本身被用作其他 class 的依赖项,那么 class 也应该被抽象出来。
public interface IDbService {
IDbConnectionFactory DBFactory { get; }
List<Customer> GetAllCustomers();
}
并让实现继承
public class DbService : IDbService {
//... code removed for brevity
}
并确保使用 IoC 容器注册所有内容。
我是一个我应该扩展的项目的新手,所以我决定使用 TDD 来快速识别我不完全理解的系统的任何问题。
有一个 class 叫做 DBService
,它 "encapsulates" 所有数据库访问。例如,有一种方法称为 getAllCustomers
,其中 returns 是 Customers
的列表。这看起来像这样(这只是一个更好理解的例子):
public class DBService
{
public IDbConnectionFactory DBFactory {
get { return DI.Container.Resolve<IDbConnectionFactory>(); }
}
public List<Customer> GetAllCustomers()
{
try
{
using (var connection = DBFactory.OpenDbConnection())
{
var dbResult = connection.Select<Customer>();
// code ommitted
}
}
catch (Exception e)
{
// code ommitted
}
}
}
另一个问题是,在开始时(在 ServiceStack AppHost.Configure
中),如果所有表不存在,都会创建所有表,并且对于某些表,如果它们存在,则会添加一些列等(这可能是更改稍后添加)
例如,当我现在必须扩展客户并添加另一个字段时,我想以 TDD 样式添加地址,但我不知道如何做。
- 我无法注入任何
DBFactory
因为 getter 是私有的 - Afaik 我不能为
OrmLiteConnectionFactory
使用:memory:
连接字符串,因为我使用的是 ServiceStack 3.9.74
那么我的选择是什么?
避免使用服务定位器anti-pattern,改用构造函数注入。尽量避免直接在依赖 classes 中使用 DI 容器。它将您的 classes 与不属于那里的问题紧密耦合,并且很难单独测试 classes。
public class DBService {
private readonly IDbConnectionFactory connectionFactory;
public DBService(IDbConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public IDbConnectionFactory DBFactory { get { return connectionFactory; } }
public List<Customer> GetAllCustomers() {
try {
using (var connection = DBFactory.OpenDbConnection()) {
var dbResult = connection.Select<Customer>();
//... code omitted for brevity
}
} catch (Exception e) {
//... code omitted for brevity
}
}
}
Select<T>
和 OpenDbConnection
看起来都像是扩展方法。我建议检查他们的期望值并模拟这些行为。
如果 DbService
本身被用作其他 class 的依赖项,那么 class 也应该被抽象出来。
public interface IDbService {
IDbConnectionFactory DBFactory { get; }
List<Customer> GetAllCustomers();
}
并让实现继承
public class DbService : IDbService {
//... code removed for brevity
}
并确保使用 IoC 容器注册所有内容。