La respuesta muy corta es no, NSubstitute no tiene nada construido para facilitar la prueba de expresiones específicas.
La respuesta mucho más larga es que hay algunas opciones que puede probar, y la mayoría de ellas implican evitar el uso directo de LINQ en la clase bajo prueba. No estoy seguro si alguna de estas son buenas ideas ya que no conozco el contexto completo, pero espero que haya alguna información aquí que pueda usar. En los siguientes ejemplos, eliminé el paso de Mapper para hacer que las muestras del código sean un poco más pequeñas.
La primera opción es hacerlo para que pueda comprobar que la expresión es la misma referencia que está esperando, lo que significa que ya no puede crearla directamente en el código bajo prueba. Por ejemplo:
//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));
}
He vertido la expresión de una clase de consultas estáticas, pero se puede usar una fábrica para encapsular mejor. Como tiene una referencia a la expresión real utilizada, puede establecer valores de retorno y verificar que las llamadas se recibieron de forma normal. También puedes probar la expresión de forma aislada.
La segunda opción lleva esto un poco más lejos mediante el uso de un patrón de especificación. Digamos que agregar el miembro siguiente a la interfaz IRepository e introducir un ISpecification:
public interface IRepository<TEntity> where TEntity : IdEntity
{
/* ...snip... */
IList<TEntity> Find(ISpecification<TEntity> query);
}
public interface ISpecification<T> { bool Matches(T item); }
entonces usted puede probar de esta manera:
//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));
}
Una vez más, se puede probar esta consulta en forma aislada para asegurarse de que hace lo que piensas
La tercera opción es captar el argumento utilizado y probarlo directamente. Esto es un poco desordenado, pero funciona:
[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 });
}
(Esto se espera que sea cada vez un poco más fácil en futuras versiones NSubstitute)
cuarta opción sería encontrar/prestado/escritura/robar algo de código que se puede comparar árboles de expresión, y usan Arg.Is (...) de NSubstitute que toma un predicado para comparar los árboles de expresión allí.
La quinta opción es no probarla en ese grado, y solo la prueba de integración usando un FacturaRepositorio real. En lugar de preocuparse por la mecánica de lo que está sucediendo, intente verificar el comportamiento real que necesita.
Mi consejo general sería ver exactamente lo que necesita probar y cómo puede escribir mejor y con más facilidad esas pruebas. Recuerde que tanto la expresión como el hecho de que se transmite deben ser probados de alguna manera, y la prueba no necesita ser una prueba unitaria. También puede valer la pena considerar si la interfaz actual de IRepository te está haciendo la vida más fácil. Podría intentar escribir las pruebas que tendría , como, y luego ver qué diseño puede extraer para respaldar esa capacidad de prueba.
Espero que esto ayude.
He estado luchando con algo similar - Me encanta ser capaz de probar todo mi LINQ, pero se me hace difícil cuando se introduce cosas como SqlFunctions que no se pueden ejecutar. http://stackoverflow.com/questions/21495980/testing-sqlfunctions-in-linq-statements - Creo que voy a ir para las pruebas de integración en su lugar – Neil