Autofixture: Cree GuardClauseAssertion alternativo que admita métodos marcados con `async`.

Creado en 1 mar. 2019  ·  12Comentarios  ·  Fuente: AutoFixture/AutoFixture

Como se discutió en # 268, la clase GuardClauseAssertion no espera a que se completen las tareas, por lo que no puede validar métodos rápidos que no

Esto es completamente comprensible, ya que el fail fast es de hecho la mejor opción. Sin embargo, parece imposible implementar un comportamiento async .

enhancement

Comentario más útil

@ploeh Básicamente, el método _cualquier_ async no es rápido. Considere el siguiente ejemplo:

`` c #
Tarea asíncrona públicaGuardedOpenGenericMethodReturningTaskResult(objeto arg)
{
if (arg == null) lanza una nueva ArgumentNullException (nameof (arg));

await Task.Yield();

return default;

}
''

Este método no lanza si lo llamas null . En su lugar, se devuelve el Task fallido. Por lo tanto, GuardClauseAssertion en su forma actual falla y se queja de la falta de una cláusula de guardia.

En una aplicación real, casi todo el código es async , por lo tanto, cada invocación es awaited y la excepción se lanza inmediatamente. Por lo tanto, está completamente bien que se viole el principio de "falla rápida" en una forma en la que debe await Task para ver la excepción.

Por supuesto, puede volver a escribir el código de alguna manera para que falle inmediatamente (cree una función privada con la palabra clave async y mueva toda la lógica allí), pero no tiene sentido hacerlo.

Todos 12 comentarios

parece imposible implementar el comportamiento _fail fast_ cuando se trata de métodos marcados con la palabra clave async .

¿Cómo es eso? ¿Puede dar un ejemplo?

@ploeh Básicamente, el método _cualquier_ async no es rápido. Considere el siguiente ejemplo:

`` c #
Tarea asíncrona públicaGuardedOpenGenericMethodReturningTaskResult(objeto arg)
{
if (arg == null) lanza una nueva ArgumentNullException (nameof (arg));

await Task.Yield();

return default;

}
''

Este método no lanza si lo llamas null . En su lugar, se devuelve el Task fallido. Por lo tanto, GuardClauseAssertion en su forma actual falla y se queja de la falta de una cláusula de guardia.

En una aplicación real, casi todo el código es async , por lo tanto, cada invocación es awaited y la excepción se lanza inmediatamente. Por lo tanto, está completamente bien que se viole el principio de "falla rápida" en una forma en la que debe await Task para ver la excepción.

Por supuesto, puede volver a escribir el código de alguna manera para que falle inmediatamente (cree una función privada con la palabra clave async y mueva toda la lógica allí), pero no tiene sentido hacerlo.

En la aplicación real, casi todo el código es async , por lo tanto, cada invocación es awaited y la excepción se lanza inmediatamente.

Ese es un buen punto; Acepto ese argumento.

A veces me desvío cuando alguien afirma o insinúa (con poca evidencia) que algo es _imposible _ ...

A veces me desvío cuando alguien afirma o insinúa (con poca evidencia) que algo es imposible ...

Sí, es bastante justo 😉

Ahora déjeme intentar pensar cómo puedo rediseñar GuardClauseAssertion para que no tenga una bandera booleana; para ser justos, tampoco me gusta. Nos vemos más tarde en PR.

Ahora déjame intentar pensar cómo puedo rediseñar GuardClauseAssertion para que no tenga una bandera booleana

Creo que, como sugirió @moodmosaic , una nueva clase podría ser un mejor diseño. Sin embargo, no he investigado mucho el problema, así que me reservo el derecho a equivocarme 😄

Aquí está la solución que he estado usando.

  1. Eliminar la palabra clave async de la firma del método
  2. Cree un método anidado con la palabra clave async
  3. Coloque las cláusulas de protección en la parte exterior del método.
  4. Llame al método anidado y devuelva los resultados

Ejemplo:

public Task<int> GetNumberAsync(MyObject obj)
{
    // Fail-fast behavior
    if (request is null)
        throw new ArgumentNullException(nameof(obj));

    async Task<int> work()
    {
        var items = await obj.GetItemsAsync(); // whatever you need to call
        return items.Count();
    }

    return work();
}

Ha sido una buena solución para mi. Gracias por tu ayuda.

@mniak Es interesante tener un ejemplo concreto de lo que @zvirja sugirió aquí .

Personalmente, no me gusta mucho porque estamos contaminando el método con "trucos" en beneficio del marco de prueba, que me huele muy mal y no quisiera que mi equipo usara este patrón.

Manténgalo abierto para implementar el soporte de forma nativa. Un día. En un futuro cercano. O solo un día.

Hola. Nos topamos con exactamente este problema y nos sorprendió que no exista una buena solución hasta ahora.
¿Hay razones para no implementar una nueva clase para esto?
No conozco los detalles internos de AutoFixture, pero si tuviéramos un MethodInfo disponible dentro de la clase GuardClauseAssertion para el método de prueba, podemos echar un vistazo a sus CustomAttributes e identificar si es un método Async o no (https: / /stackoverflow.com/a/20350646). Entonces, tal vez, un interruptor (bool versus nueva clase) ni siquiera sea necesario.

@zvirja @aivascu ¿ podríamos reconsiderar esto? Realmente no veo por qué en 2021 los métodos asíncronos no se pueden probar correctamente.

@Kralizek si leo la situación correctamente, la solicitud no ha sido rechazada, e incluso hay un PR que la arregla.
Eché un vistazo breve a las relaciones públicas y debo decir que estoy de acuerdo con los comentarios que recibió.
Entonces, lo único que queda es implementar la retroalimentación o presentar un nuevo RP con la retroalimentación implementada.

No pude ver el PR vinculado en la aplicación móvil 😅

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

ploeh picture ploeh  ·  3Comentarios

Ridermansb picture Ridermansb  ·  4Comentarios

zvirja picture zvirja  ·  3Comentarios

tomasaschan picture tomasaschan  ·  3Comentarios

zvirja picture zvirja  ·  4Comentarios