Asserire un'eccezione utilizzando XUnit


111

Sono un principiante di XUnit e Moq. Ho un metodo che accetta la stringa come argomento.Come gestire un'eccezione usando XUnit.

[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException() {
    //arrange
    ProfileRepository profiles = new ProfileRepository();
    //act
    var result = profiles.GetSettingsForUserID("");
    //assert
    //The below statement is not working as expected.
    Assert.Throws<ArgumentException>(() => profiles.GetSettingsForUserID(""));
}

Metodo in prova

public IEnumerable<Setting> GetSettingsForUserID(string userid)
{            
    if (string.IsNullOrWhiteSpace(userid)) throw new ArgumentException("User Id Cannot be null");
    var s = profiles.Where(e => e.UserID == userid).SelectMany(e => e.Settings);
    return s;
}

1
Cosa intendi con "non funziona come previsto"? (Inoltre, formatta il codice in modo più leggibile. Usa l'anteprima e pubblica quando appare come vorresti che fosse se lo leggessi.)
— Jon Skeet

4
Suggerimento: stai chiamando GetSettingsForUserID("")prima di iniziare a chiamare Assert.Throws. La Assert.Throwschiamata non può aiutarti. Suggerirei di essere meno rigido riguardo agli AAA ...
— Jon Skeet

Risposte:


183

L' espressione Assert.Throws rileverà l'eccezione e asserirà il tipo. Tuttavia stai chiamando il metodo sotto test al di fuori dell'espressione assert e quindi fallendo il test case.

[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException()
{
    //arrange
    ProfileRepository profiles = new ProfileRepository();
    // act & assert
    Assert.Throws<ArgumentException>(() => profiles.GetSettingsForUserID(""));
}

Se sei deciso a seguire AAA puoi estrarre l'azione nella sua variabile.

[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException()
{
    //arrange
    ProfileRepository profiles = new ProfileRepository();
    //act
    Action act = () => profiles.GetSettingsForUserID("");
    //assert
    var exception = Assert.Throws<ArgumentException>(act);
    //The thrown exception can be used for even more detailed assertions.
    Assert.Equal("expected error message here", exception.Message);
}

Notare come l'eccezione possa essere utilizzata anche per asserzioni dettagliate sulla modalità


5
Se si utilizzano metodi asincroni, Visual Studio genera un avviso con la sintassi precedente. Preferisce questo:async Task act() => await service.DoTheThingAsync(); await Assert.ThrowsAsync<InvalidOperationException>(act);
— Alec

5
In realtà per me ciò ha provocato un errore, "non può convertire implicitamente Task in Func <Task>", mentre se lo metto solo Task act() => service.DoTheThingAsync(); await Assert.ThrowsAsync<InvalidOperationException>(act);allora è soddisfatto e funziona bene.
— Alec

in che modo lavorare con async / await influisce su questo? quando provo a farlo usando ThrowsAsync nel mio test, non raggiunge mai la linea Assert.Equal poiché genera correttamente l'errore e chiude il test. testare l'acqua per vedere se questa dovrebbe essere una nuova domanda ...
— nathanjw

@AlecDenholm Grazie! Questa è l'unica cosa che ha funzionato per me. Penso che alcuni degli altri suggerimenti non funzionino correttamente per le cose asincrone.
— marchio

45

Se vuoi essere rigido su AAA, puoi usare Record.Exception da xUnit per catturare l'eccezione nella tua fase Act.

È quindi possibile effettuare asserzioni basate sull'eccezione acquisita nella fase Asserzione.

Un esempio di ciò può essere visto nei test xUnits .

[Fact]
public void Exception()
{
    Action testCode = () => { throw new InvalidOperationException(); };

    var ex = Record.Exception(testCode);

    Assert.NotNull(ex);
    Assert.IsType<InvalidOperationException>(ex);
}

Dipende da te quale percorso desideri seguire ed entrambi i percorsi sono completamente supportati da ciò che fornisce xUnit.


1
FWIW, questa soluzione è ottima se hai bisogno di convalidare il messaggio di eccezione, ecc. Penso che sia quando potresti usare Record.Exception.
— Jeff LaFay

@JeffLaFay Apprezzo di essere un po 'in ritardo alla festa qui, in che modo sarebbe diverso dall'uso var exception = Assert.Throws<InvalidOperationException>(testCode);e dall'affermazione exception.Message? o è solo un altro modo per ottenere la stessa cosa?
— ColinM

3

Potresti prendere in considerazione qualcosa di simile se vuoi attenersi ad AAA:

// Act 
Task act() => handler.Handle(request);

// Assert
await Assert.ThrowsAsync<MyExpectedException>(act);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.