我知道适当的SOLID原则与IOC相结合意味着您可以通过模拟类依赖性来对所有代码进行单元测试,而无需实际访问数据库。在工作讨论之后,我的问题是,是否值得实际测试您的数据访问层本身。
如果您已正确分离代码,那么您的数据访问方法通常会非常小。这是一个人为的例子:
public class InvoiceQueries
{
public IEnumerable<Customer> GetAllCustomersWithOverdueInvoices(TimeSpan timeOverdue)
{
var results =
from invoice in Invoices
where invoice.DateDue - timeOverdue > DateTime.Now
select invoice.Customer;
return results;
}
}
是否值得编写自动化测试(它不是单元测试)来检查您的查询是否正确编写?也许连接到真实的数据库,甚至是内存数据库,插入一些测试数据然后检查你的方法是否返回那些客户?
一位同事说你绝对应该 - 一切都应该进行测试。对我来说,在构建服务器上启动并运行某种形式的T-SQL数据库似乎需要付出大量的工作,更不用说这些测试几乎肯定会非常慢,而且用处可疑。
谁有实际测试(以孤立方式)他们的数据访问层的经验?
答案 0 :(得分:1)
是的,它应该进行测试,并且值得花时间让它工作(否则你会浪费时间手动测试它)。是的,它比单元测试慢得多,但你可以让它足够快(内存中的数据库,所有测试的一次数据库启动,测试组等)。当然,您需要将db层与业务逻辑隔离
答案 1 :(得分:0)
经过一番商议,我和我的同事提出了一种将查询与持久层分开的方法。我在下面拼凑了一个简单的例子:
public class Invoice
{
public int Id {get; set;}
public DateTime DueOn {get; set;}
public DateTime MadeOn {get; set;}
public decimal Total {get; set;}
public Customer Customer {get;set;}
}
public class Customer
{
public int Id {get; set;}
public string Name {get; set;}
}
public class OverdueInvoice
{
public int CustomerId {get; set;}
public int InvoiceId {get; set;}
public string CustomerName {get; set;}
public decimal Total {get; set;}
}
public class InvoiceQueries
{
private readonly IReadRepository<Invoice> _invoices;
public InvoiceQueries(IReadRepository<Invoice> invoices)
{
_invoices = invoices;
}
public IEnumerable<OverdueInvoice> GetAllOverdueInvoices(TimeSpan timeOverdue)
{
return _invoices
.FindAll(invoice => invoice.DueOn - timeOverdue > DateTime.Now)
.Select(Map);
}
private OverdueInvoice Map(Invoice invoice)
{
return new OverdueInvoice
{
CustomerId = invoice.Customer.Id,
InvoiceId = invoice.Id,
CustomerName = invoice.Customer.Name,
Total = invoice.Total,
};
}
}
public class InMemoryInvoicesRepository : IReadRepository<Invoice>, IWriteRepository<Invoice>
{
private List<Invoice> _backingStore;
public InMemoryInvoicesRepository() : this(new List<Invoice>())
{}
public InMemoryInvoicesRepository(List<Invoice> backingStore)
{
_backingStore = backingStore;
}
public IEnumerable<Invoice> FindAll(Predicate<Invoice> predicate)
{
return _backingStore.FindAll(predicate);
}
public void Add(Invoice item)
{
_backingStore.Add(item);
}
}
public interface IReadRepository<T>
{
IEnumerable<T> FindAll(Predicate<T> predicate);
}
public interface IWriteRepository<T>
{
void Add(T item);
}
将数据访问分隔为“查询”对象和“存储库”对象允许您在测试时将存储库替换为内存中集合。这样,您可以使用您想要的任何对象填充List,然后通过针对该列表运行查询来测试您的查询层。存储库是一个非常愚蠢的对象,它会接收您的查询并将其传递给您的ORM(实际上,这个Func可能必须被Expression&gt;替换)。