unit test await async c# moq async-await xunit.net

c# - test - xUnit y Moq no son compatibles con async-esperan palabras clave



c# test await (2)

Cambie su método de prueba de unidad para devolver Task lugar de void , y debería funcionar. El soporte para las pruebas unitarias async void se está considerando para una versión futura .

Describo en detalle por qué las pruebas unitarias asíncronas no funcionan de forma predeterminada en mi blog. (Los ejemplos de mi blog utilizan MSTest, pero los mismos problemas existían en todos los demás programas de prueba, incluido xUnit pre-1.9).

Estoy intentando descubrir cómo aplicar async y esperar palabras clave a mis pruebas xUnit. Estoy usando xUnit 1.9 y Async CTP 1.3. Aquí está mi caso de prueba

Tengo una interfaz que especifica una llamada de 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, deseo verificar que el método DoThatAsyncOperation esté llamando 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 async y await palabras clave. Cuando se ejecuta, pasa erróneamente como Moq debe afirmar que la verificación falla. Cualquier código después de la llamada a sut.DoThatAsyncOperation("test"); no corre

[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 se configura sin las palabras clave de espera y asíncrona y pasa bien.

¿Es este comportamiento esperado para xUnit y Moq?

Actualizar

Gracias por el comentario de Stephen, logré arreglar la primera prueba haciendo dos cambios. La prueba ahora devuelve una tarea en lugar de anular y el simulacro 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")); }


Intenté usar el código de su ''Actualización'', pero estaba parando en el método asíncrono que me estaba burlando.

var tcs = new TaskCompletionSource<T>(); tcs.SetResult(default(T)); mock.Setup(x => x.AnAsyncMethod(It.IsAny<T>())).Returns(tcs.Task);

Así que para arreglar eso tuve que cambiar el método de ''Retorno'':

mock.Setup(x => x.AnAsyncMethod(It.IsAny<T>())).Returns(()=> { return tcs.Task; } );