非常简短的回答是否定的,NSubstitute没有任何内置它使测试具体表现更加容易。
长得多的答案是有,你可以尝试几个选项,其中大部分涉及避免被测类直接使用LINQ的。我不确定这些是否是好主意,因为我不知道整个背景,但希望在这里可以使用一些信息。在下面的例子中,我已经消除了Mapper步骤,以使代码样本更小一些。
第一种选择是让这样你就可以检查表达式是你期望的相同的参考,这意味着你不能再在你的代码中直接创建测试。例如:
//Class under test uses:
_invoiceRepository.Find(Queries.UnprocessedConfirmedOrders)
[Test]
public void TestUnprocessedInvoices()
{
IList<InvoiceDTO> expectedResults = new List<InvoiceDTO>();
_invoiceRepository.Find(Queries.UnprocessedConfirmedOrders).Returns(expectedResults);
Assert.That(_sut.GetUnprocessedInvoices(), Is.SameAs(expectedResults));
}
我已经将表达式转储到静态查询类上,但您可以使用工厂来更好地封装它。由于您使用的是实际表达式的引用,因此可以设置返回值并检查正常接收的调用。您也可以单独测试表达式。
第二个选项通过使用规格模式进一步考虑了这一点。说你下面的成员添加到IRepository接口,并引入ISpecification:
public interface IRepository<TEntity> where TEntity : IdEntity
{
/* ...snip... */
IList<TEntity> Find(ISpecification<TEntity> query);
}
public interface ISpecification<T> { bool Matches(T item); }
然后,您可以测试它是这样的:
//Class under test now uses:
_invoiceRepository.Find(new UnprocessedConfirmedOrdersQuery());
[Test]
public void TestUnprocessedInvoicesUsingSpecification()
{
IList<InvoiceDTO> expectedResults = new List<InvoiceDTO>();
_invoiceRepository.Find(Arg.Any<UnprocessedConfirmedOrdersQuery>()).Returns(expectedResults);
Assert.That(_sut.GetUnprocessedInvoices(), Is.SameAs(expectedResults));
}
同样,你可以隔离测试此查询,以确保它做你的想法。
第三种方法是捕捉使用的参数并直接对其进行测试。这是一个有点乱,但工程:
[Test]
public void TestUnprocessedInvoicesByCatchingExpression()
{
Expression<Func<InvoiceDTO, bool>> queryUsed = null;
IList<InvoiceDTO> expectedResults = new List<InvoiceDTO>();
_invoiceRepository
.Find(i => true)
.ReturnsForAnyArgs(x =>
{
queryUsed = (Expression<Func<InvoiceDTO, bool>>)x[0];
return expectedResults;
});
Assert.That(_sut.GetUnprocessedInvoices(), Is.SameAs(expectedResults));
AssertQueryPassesFor(queryUsed, new InvoiceDTO { IsProcessed = false, IsConfirmed = true });
AssertQueryFailsFor(queryUsed, new InvoiceDTO { IsProcessed = true, IsConfirmed = true });
}
(希望这将让未来NSubstitute版本更容易一点)
第四个选项是要找到/借/写/窃取一些代码,可以比较表达式树,并使用NSubstitute的Arg.Is(...)来取得一个谓词来比较表达式树。
第五种方法是不单元测试它到那个程度,而只是使用真正的InvoiceRepository进行集成测试。不要担心所发生的事情的机制,请尝试验证您所需的实际行为。
我的一般建议是看看你需要测试什么,以及如何才能最好,最容易编写这些测试。请记住,表达式和它传递的事实都需要以某种方式进行测试,并且测试不需要是单元测试。也许值得考虑一下,当前的IRepository接口是否让你的生活更轻松。您可以尝试编写测试,比如,然后查看可以推出哪些设计来支持可测试性。
希望这会有所帮助。
我一直在摔跤类似的东西 - 我真的很喜欢能够测试我所有的LINQ,但我发现很难,当你介绍这样的事情不能被执行SqlFunctions。 http://stackoverflow.com/questions/21495980/testing-sqlfunctions-in-linq-statements - 我想我只是去集成测试,而不是 – Neil 2014-02-01 09:21:16