Tengo las siguientes cuatro pruebas y la última se cuelga cuando la ejecuto. Por qué pasó esto:
[Test]
public void CheckOnceResultTest()
{
Assert.IsTrue(CheckStatus().Result);
}
[Test]
public async void CheckOnceAwaitTest()
{
Assert.IsTrue(await CheckStatus());
}
[Test]
public async void CheckStatusTwiceAwaitTest()
{
Assert.IsTrue(await CheckStatus());
Assert.IsTrue(await CheckStatus());
}
[Test]
public async void CheckStatusTwiceResultTest()
{
Assert.IsTrue(CheckStatus().Result); // This hangs
Assert.IsTrue(await CheckStatus());
}
private async Task<bool> CheckStatus()
{
var restClient = new RestClient(@"https://api.test.nordnet.se/next/1");
Task<IRestResponse<DummyServiceStatus>> restResponse = restClient.ExecuteTaskAsync<DummyServiceStatus>(new RestRequest(Method.GET));
IRestResponse<DummyServiceStatus> response = await restResponse;
return response.Data.SystemRunning;
}
Utilizo este método de extensión para restsharp RestClient :
public static class RestClientExt
{
public static Task<IRestResponse<T>> ExecuteTaskAsync<T>(this RestClient client, IRestRequest request) where T : new()
{
var tcs = new TaskCompletionSource<IRestResponse<T>>();
RestRequestAsyncHandle asyncHandle = client.ExecuteAsync<T>(request, tcs.SetResult);
return tcs.Task;
}
}
public class DummyServiceStatus
{
public string Message { get; set; }
public bool ValidVersion { get; set; }
public bool SystemRunning { get; set; }
public bool SkipPhrase { get; set; }
public long Timestamp { get; set; }
}
¿Por qué se cuelga la última prueba?

async voidmétodos de prueba de unidad en absoluto; simplemente no funcionarán. Sin embargo, NUnit sí. Dicho esto, estoy de acuerdo con el principio general de preferirasync Tasksobreasync void.Respuestas:
Se encuentra con la situación de bloqueo estándar que describo en mi blog y en un artículo de MSDN : el
asyncmétodo está intentando programar su continuación en un hilo que está bloqueado por la llamada aResult.En este caso,
SynchronizationContextNUnit utiliza el suyo para ejecutarasync voidmétodos de prueba. Intentaría usarasync Taskmétodos de prueba en su lugar.fuente
asynctodo el camino" (como se señala en mi artículo de MSDN). En otras palabras, como dice el título de mi blog, "no bloquee el código asíncrono".Wait()con hacer el método de llamadaasync. Pero para mí, esto parece estar empujando el problema hacia arriba. En algún momento, algo tiene que ser administrado sincrónicamente. ¿Qué sucede si mi función es intencionadamente sincrónica porque administra hilos de trabajo de larga ejecuciónTask.Run()? ¿Cómo espero a que termine sin bloquearse dentro de mi prueba NUnit?At some point, something has to be managed synchronously.- en absoluto. Para aplicaciones de IU, el punto de entrada puede ser unasync voidcontrolador de eventos. Para aplicaciones de servidor, el punto de entrada puede ser unaasync Task<T>acción. Es preferible usarasyncambos para evitar el bloqueo de hilos. Puede hacer que su prueba de NUnit sea síncrona o asíncrona; si es asíncrono, hágalo enasync Tasklugar deasync void. Si es sincrónico, no debería tener un,SynchronizationContextasí que no debería haber un punto muerto.Adquisición de un valor a través de un método asíncrono:
Llamar sincrónicamente un método asíncrono
No se producirán problemas de punto muerto debido al uso de Task.Run.
fuente
async voidmétodos de prueba unitaria y eliminar las garantías del mismo hilo proporcionadas porSynchronizationContextel sistema bajo prueba..GetAwaiter().GetResult()lugar de hacerlo.Resultpara que ninguno quedeExceptionenvuelto.Puede evitar el punto muerto que se agrega
ConfigureAwait(false)a esta línea:=>
Describí este escollo en la publicación de mi blog Escollos de async / await
fuente
Está bloqueando la IU utilizando la propiedad Task.Result. En la documentación de MSDN , han mencionado claramente que,
La mejor solución para este escenario sería eliminar los modos de espera y asíncrono de los métodos y usar solo la Tarea donde devuelve el resultado. No alterará su secuencia de ejecución.
fuente
Si no recibe ninguna devolución de llamada o el control se cuelga, después de llamar a la función asíncrona de servicio / API, debe configurar Context para devolver un resultado en el mismo contexto llamado.
Utilizar
TestAsync().ConfigureAwait(continueOnCapturedContext: false);Se enfrentará a este problema solo en aplicaciones web, pero no en
static void main.fuente
ConfigureAwaitevita el interbloqueo en ciertos escenarios al no ejecutarse en el contexto del hilo original