Start Debugging

NUnit 5: Assert.ThrowsAsync agora retorna uma Task, e uma sem await passa silenciosamente

O NUnit 5.0.0 torna Assert.ThrowsAsync, CatchAsync e DoesNotThrowAsync realmente assíncronos. Esqueça o await e a asserção nunca é executada. Veja o que quebra, o que a regra NUnit2059 do NUnit.Analyzers detecta e as outras mudanças do NUnit 5 a verificar antes de atualizar.

O NUnit 5.0.0 foi lançado em 27 de setembro de 2026. Os mantenedores o descrevem como uma versão major pequena, e a maioria das mudanças incompatíveis transforma falhas em runtime em erros de compilação. Uma mudança vai no sentido oposto: se você atualizar sem cuidado, um teste que falha pode passar a passar.

ThrowsAsync costumava bloquear, agora retorna uma Task

No NUnit 4, Assert.ThrowsAsync<T>, Assert.CatchAsync e Assert.DoesNotThrowAsync tinham nomes assíncronos, mas executavam o delegate de forma síncrona, bloqueando a thread chamadora, e retornavam a exceção diretamente. A issue #4384 corrigiu isso na 5.0.0: os três agora retornam uma Task e precisam de await.

// NUnit 4.6.1
var ex = Assert.ThrowsAsync<ArgumentException>(async () => await DoAsync());

// NUnit 5.0.0
var ex = await Assert.ThrowsAsync<ArgumentException>(async () => await DoAsync());

O novo formato é o correto. O problema é o código que você já tem.

A aprovação silenciosa

Testes antigos chamam ThrowsAsync de um método de teste void comum. No NUnit 5 isso ainda compila: a Task retornada é descartada e, como o método não é async, o compilador sequer emite CS4014. Executei isto no .NET SDK 10.0.302 com NUnit3TestAdapter 6.3.0, em que DoesNotThrowAsync nunca lança exceção:

static async Task DoesNotThrowAsync() => await Task.Delay(10);

[Test]
public void Unawaited()
{
    var ex = Assert.ThrowsAsync<ArgumentException>(async () => await DoesNotThrowAsync());
}

[Test]
public async Task Awaited()
{
    var ex = await Assert.ThrowsAsync<ArgumentException>(async () => await DoesNotThrowAsync());
}

Os resultados:

ConfiguraçãoUnawaitedAwaited
NUnit 4.6.1falha (correto)CS1061, ArgumentException não tem GetAwaiter
NUnit 5.0.0, NUnit.Analyzers 4.13.0passafalha (correto)
NUnit 5.0.0, NUnit.Analyzers 4.14.0 ou 4.15.0erro de build NUnit2059falha (correto)

A linha do meio é a que preocupa. O teste que deveria detectar a ausência de uma ArgumentException fica verde, e nada na saída dos testes indica que a asserção nunca foi executada.

Deixe o analisador fazer a migração

O NUnit.Analyzers 4.14.0 adicionou o NUnit2059, “Method ‘ThrowsAsync’ returns a Task and is not being observed”, reportado como erro por padrão. Sua correção automática adiciona o await e muda o método que o contém para async Task. Portanto, a ordem da atualização importa:

<PackageReference Include="NUnit" Version="5.0.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.15.0" />
<PackageReference Include="NUnit3TestAdapter" Version="6.3.0" />

Atualize o analisador no mesmo commit que o framework. Se seus projetos fixam o NUnit.Analyzers de forma centralizada em Directory.Packages.props em uma versão mais antiga, ou o removeram, o build continua verde e você cai na linha da aprovação silenciosa.

As outras mudanças do NUnit 5 que valem um grep

Se você está decidindo se o NUnit ainda é o framework certo para um novo projeto, minha comparação entre xUnit v3, NUnit e MSTest foi medida no NUnit 4.6.1. Os números lá são anteriores à 5.0.0, mas a recomendação não depende de nada que esta versão tenha mudado.

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Voltar