非常簡短的回答是否定的,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