Use o método NUnit Assert.Throws ou o atributo ExpectedException?

146

Descobri que essas parecem ser as duas principais maneiras de testar exceções:

Assert.Throws<Exception>(()=>MethodThatThrows());

[ExpectedException(typeof(Exception))]

Qual destes seria o melhor? Um oferece vantagens sobre o outro? Ou é simplesmente uma questão de preferência pessoal?

SamuelDavis
fonte
3
Uma terceira opção é o estilo fluente:Assert.That(() => MethodThatThrows(), Throws.Exception)
Jack Ukleja 07/10
1
O NUnit versão 3 e posterior não oferece mais suporte ao ExpectedExceptionatributo, portanto, para a versão 3+, apenas a Assert.Throwsvariante é relevante.
joanlofe
Por que é tão? Que o Nunit3 decidiu abandonar esse suporte? Estava pesquisando no Google e não consegui encontrar uma explicação para isso ... O JUnit ainda suporta esse caminho, não é?
ahaaman

Respostas:

92

A primeira permite testar mais de uma exceção, com várias chamadas:

Assert.Throws(()=>MethodThatThrows());
Assert.Throws(()=>Method2ThatThrows());

O segundo permite apenas testar uma exceção por função de teste.

sugestão x
fonte
25
Um teste deve testar apenas um pouco distinto da lógica; portanto, testar dois erros no mesmo teste de unidade não é considerado uma prática ruim?
SamuelDavis 22/02
5
@ SamuelDavis - em geral, você não gostaria de testar casos diferentes no mesmo teste. No entanto, pode haver algum caso de uso para vários Assert.Throws.
chue x
3
De qualquer maneira, aqui você obtém a exceção como um parâmetro, que permite afirmar detalhes na exceção. Além disso, o uso de "Exceção esperada" não protege você para o mesmo tipo de exceção que está sendo lançado em outra chamada de método. Aqui, você direciona o método exato e não o teste inteiro. Embora seu teste deva chamar muito pouco código, você nunca está seguro demais. Especialmente quando o código se torna complexo e / ou exceção muito genérica. Coisas como "ArgumentNullExceptions" podem ser lançadas muito e, por exemplo, seriam facilmente perdidas usando a ExpectedException. Assert.Throws não perderia.
Gil Sand
254

A principal diferença é:

ExpectedException()O atributo faz com que o teste seja aprovado se ocorrer uma exceção em qualquer lugar do método de teste.
O uso de Assert.Throws()permite especificar o exactlocal do código onde a exceção é esperada.

O NUnit 3.0 descarta ExpectedExceptiontotalmente o suporte oficial .

Então, eu definitivamente prefiro usar o Assert.Throws()método do que o ExpectedException()atributo.

Alexander Stepaniuk
fonte
7
Esta é de longe a resposta correta. Aliás, Assert.Throws () também retorna a exceção, o que pode permitir uma inspeção adicional das propriedades da exceção, se elas forem importantes para você.
Perfeccionista
1
Por fim, responda por que não consigo fazer com que o ExpectedException funcione .. com a versão 3. #
21 JanT17:
2
Aqui está o link github.com/nunit/docs/wiki/Breaking-Changes - ExpectedExceptionAttribute não é mais suportado.
Anton Lyhin
Para alterar isso para funcionar no NUnit 3.0, altere-o para o seguinte #
Andrei Krasutski 02/02/19
38

Prefiro assert.throws, pois me permite verificar e afirmar outras condições após a exceção ser lançada.

    [Test]
    [Category("Slow")]
    public void IsValidLogFileName_nullFileName_ThrowsExcpetion()
    {
        // the exception we expect thrown from the IsValidFileName method
        var ex = Assert.Throws<ArgumentNullException>(() => a.IsValidLogFileName(""));

        // now we can test the exception itself
        Assert.That(ex.Message == "Blah");

    }
Mike Parkhill
fonte
Essa é uma das melhores respostas, é bastante comum que você queira verificar se algo entrou em um estado com erro após a exceção ser lançada.
Rhys Bevilaqua
11

Você também pode digitar com firmeza o erro que está esperando (como a versão antiga do attrib).

Assert.Throws<System.InvalidOperationException>(() => breakingAction())
Reverendo Sfinks
fonte