Estoy intentando descubrir cómo aplicar la asincrónica y esperar palabras clave para mis pruebas de xUnit. Estoy usando xUnit 1.9 y Async CTP 1.3. Aquí está mi caso de pruebaxUnit y Moq no son compatibles con async: aguarde las palabras clave
tengo una interfaz que especifica llamada de un método asíncrono
public interface IDoStuffAsync
{
Task AnAsyncMethod(string value);
}
tengo una clase que consume la interfaz y llama al método asíncrono
public class UseAnAsyncThing
{
private readonly IDoStuffAsync _doStuffAsync;
public UseAnAsyncThing(IDoStuffAsync doStuffAsync)
{
_doStuffAsync = doStuffAsync;
}
public async Task DoThatAsyncOperation(string theValue)
{
await _doStuffAsync.AnAsyncMethod(theValue);
}
}
En mis pruebas me deseo comprobar que el método DoThatAsyncOperation
llama al método con el valor correcto, así que me burlo de la interfaz y uso el Moq para verificar la llamada
[Fact]
public async void The_test_will_pass_even_though_it_should_fail()
{
var mock = new Mock<IDoStuffAsync>();
var sut = new UseAnAsyncThing(mock.Object);
mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>()));
await sut.DoThatAsyncOperation("test");
// This won't throw a Moq.MockExcpetion so the test appears to pass
// However it does not run
mock.Verify(x => x.AnAsyncMethod("fail"));
}
Esta prueba utiliza las palabras clave async
y await
. Cuando se ejecuta, pasa erróneamente ya que Moq debería afirmar que la verificación falla. Cualquier código después de la llamada a sut.DoThatAsyncOperation("test");
no se ejecuta
[Fact]
public void This_will_work_and_assert_the_reslt()
{
var mock = new Mock<IDoStuffAsync>();
var sut = new UseAnAsyncThing(mock.Object);
mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>()));
sut.DoThatAsyncOperation("test").ContinueWith(y => { });
// This won't throw a Moq.MockExcpetion so the test appears to pass
// However it does not run
mock.Verify(x => x.AnAsyncMethod("fail"));
}
Esta prueba está configurada sin las palabras clave esperar, y al asincrónicos y pasa bien.
¿Es este comportamiento esperado para xUnit y Moq?
actualización
Gracias por el comentario de Esteban I lograron fijar la primera prueba, haciendo dos cambios. La prueba ahora devuelve una tarea en lugar de vacía y la simulación también devuelve una tarea.
[Fact]
public async Task The_test_will_pass_even_though_it_should_fail()
{
var mock = new Mock<IDoStuffAsync>();
var sut = new UseAnAsyncThing(mock.Object);
mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>())).ReturnAsync(true);
await sut.DoThatAsyncOperation("test");
// This now fails as it should
mock.Verify(x => x.AnAsyncMethod("fail"));
}
Gracias por el párrafo anterior actualización. TaskCompletionSource fue la clave que estaba buscando para burlarse de mi método asíncrono mediante MOQ. –
Philippe
En lugar de crear explícitamente un TaskCompletionSource simplemente podría utilizar Task.FromResult: 'mock.Setup (x => x.AnAsyncMethod (It.IsAny())) devuelve (Task.FromResult (verdadero));' –
sapphiremirage
. También puede usar mock.Setup (x => x.AnAsyncMethod (It.IsAny())). ReturnAsync (true); para evitar configurar la tarea –