Autofixture: Crie GuardClauseAssertion alternativo que ofereça suporte a métodos marcados com `async`.

Criado em 1 mar. 2019  ·  12Comentários  ·  Fonte: AutoFixture/AutoFixture

Conforme discutido em # 268, a classe GuardClauseAssertion não espera a conclusão das tarefas, tornando-a incapaz de validar métodos rápidos sem

Isso é completamente compreensível, uma vez que a falha rápida é de fato a melhor opção. No entanto, parece impossível implementar o comportamento de async .

enhancement

Comentários muito úteis

@ploeh Basicamente, o método _any_ async não é rápido para falhas. Considere o seguinte exemplo:

`` `c #
tarefa assíncrona públicaGuardedOpenGenericMethodReturningTaskResult(objeto arg)
{
if (arg == null) lança um novo ArgumentNullException (nameof (arg));

await Task.Yield();

return default;

}
`` `

Este método não joga se você chamá-lo de null . Em vez disso, o Task falha é retornado. Portanto, a GuardClauseAssertion em sua forma atual falha e reclama sobre a ausência da cláusula de proteção.

Na aplicação real, quase todo o código é async , portanto, cada invocação é awaited e a exceção é lançada imediatamente. Portanto, está tudo bem que o princípio de "falha rápida" seja violado de uma forma que você deve await Tarefa para ver a exceção.

Claro, você pode reescrever o código de alguma forma para fazê-lo falhar imediatamente (criar função privada com a palavra-chave async e mover toda a lógica para lá), mas não há nenhum sentido prático para fazer isso.

Todos 12 comentários

parece impossível implementar o comportamento _fail fast_ ao lidar com métodos marcados com a palavra-chave async .

Como assim? você pode dar um exemplo?

@ploeh Basicamente, o método _any_ async não é rápido para falhas. Considere o seguinte exemplo:

`` `c #
tarefa assíncrona públicaGuardedOpenGenericMethodReturningTaskResult(objeto arg)
{
if (arg == null) lança um novo ArgumentNullException (nameof (arg));

await Task.Yield();

return default;

}
`` `

Este método não joga se você chamá-lo de null . Em vez disso, o Task falha é retornado. Portanto, a GuardClauseAssertion em sua forma atual falha e reclama sobre a ausência da cláusula de proteção.

Na aplicação real, quase todo o código é async , portanto, cada invocação é awaited e a exceção é lançada imediatamente. Portanto, está tudo bem que o princípio de "falha rápida" seja violado de uma forma que você deve await Tarefa para ver a exceção.

Claro, você pode reescrever o código de alguma forma para fazê-lo falhar imediatamente (criar função privada com a palavra-chave async e mover toda a lógica para lá), mas não há nenhum sentido prático para fazer isso.

Na aplicação real, quase todo o código é async , portanto, cada invocação é awaited e a exceção é lançada imediatamente.

Esse é um ponto justo; Eu aceito esse argumento.

Às vezes fico desviado quando alguém afirma ou insinua (com poucas evidências) que algo é _impossível _...

Às vezes fico desviado quando alguém afirma ou insinua (com poucas evidências) que algo é impossível ...

Sim, é justo 😉

Agora, deixe-me tentar pensar como posso redesenhar GuardClauseAssertion para não ter uma bandeira booleana - eu também não gosto, para ser justo. Te vejo mais tarde no PR.

Agora, deixe-me tentar pensar como posso redesenhar GuardClauseAssertion para não ter uma bandeira booleana

Eu acho que, como sugeriu @moodmosaic , uma nova classe pode ser um design melhor. Eu não pesquisei muito sobre o problema, então me reservo o direito de estar errado 😄

Aqui está a solução que tenho usado.

  1. Remova a palavra-chave async da assinatura do método
  2. Crie um método aninhado com a palavra-chave async
  3. Coloque as cláusulas de guarda na parte externa do método
  4. Chame o método aninhado e retorne os resultados

Exemplo:

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();
}

Tem sido uma boa solução para mim. Obrigado pela ajuda.

@mniak Interessante ter um exemplo concreto do que @zvirja sugeriu aqui .

Pessoalmente, eu realmente não gosto disso porque estamos poluindo o método com "truques" para o benefício do framework de testes, que cheira muito mal para mim e eu não gostaria que minha equipe usasse esse padrão.

Mantenha-o aberto para implementar o suporte de maneira nativa. Um dia. Num futuro próximo. Ou apenas um dia.

Oi. Nós tropeçamos exatamente nesse problema e ficamos surpresos que nenhuma boa solução existe até agora.
Existem razões para não implementar uma nova classe para isso?
Não sei os detalhes internos do AutoFixture, mas se quisermos ter um MethodInfo disponível dentro da classe GuardClauseAssertion para o Method-to-Test, podemos dar uma olhada em seus CustomAttributes e identificar se é um método Async ou não (https: / /stackoverflow.com/a/20350646). Então, talvez, uma troca (bool vs. nova classe) nem seja necessária.

@zvirja @aivascu podemos reconsiderar isso? Eu realmente não vejo por que em 2021 os métodos assíncronos não podem ser testados corretamente.

@Kralizek se eu li a situação corretamente, o pedido não foi rejeitado e há até um PR que corrige isso.
Dei uma olhada rápida no PR e devo dizer que concordo com o feedback que ele recebeu.
Portanto, a única coisa que resta é implementar o feedback ou enviar um novo PR com o feedback implementado.

Não consegui ver o PR vinculado no aplicativo móvel 😅

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

TroyHouston picture TroyHouston  ·  6Comentários

ecampidoglio picture ecampidoglio  ·  7Comentários

ploeh picture ploeh  ·  7Comentários

Ephasme picture Ephasme  ·  3Comentários

zvirja picture zvirja  ·  8Comentários