Очень короткий ответ - нет, 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 это будет немного легче)
Четвертый вариант - найти / одолжить / написать / украсть некоторый код, который может сравнивать деревья выражений, и использовать Arg.Is (...) NSubstitute, который принимает предикат для сравнения деревьев выражений.
Пятый вариант - это не модульное тестирование до такой степени, а просто интеграционное тестирование с использованием реального InvoiceRepository. Вместо того, чтобы беспокоиться о механике происходящего, попробуйте проверить фактическое поведение, которое вам требуется.
Мой общий совет - посмотреть, что именно нужно тестировать, и как вы можете лучше и легче всего написать эти тесты. Помните, что и выражение, и тот факт, что оно передается, нужно как-то проверить, и тест не обязательно должен быть модульным. Также стоит подумать о том, облегчает ли ваша жизнь текущий интерфейс IRepository. Вы можете попробовать написать тесты, которые хотели бы иметь , а затем посмотреть, какой дизайн вы можете использовать для поддержки этой тестируемости.
Надеюсь, это поможет.