Come faccio a controllare "non si è verificata alcuna eccezione" nel mio unit test MSTest?


89

Sto scrivendo uno unit test per questo metodo che restituisce "void". Vorrei avere un caso in cui il test viene superato quando non vengono generate eccezioni. Come lo scrivo in C #?

Assert.IsTrue(????)

(La mia ipotesi è che questo sia il modo in cui dovrei controllare, ma cosa c'è in "???")

Spero che la mia domanda sia abbastanza chiara.


Stai usando MSTest o NUnit?
Matt Grande

2
In MSTest le eccezioni non rilevate causeranno automaticamente il fallimento dei test. Stai cercando di tenere conto delle eccezioni rilevate?
Phil

Puoi cercare "try-catch per C #" e questo ti istruirà su come gestire le eccezioni che vengono generate o meno.
Foggzie

1
If NUnit, guarda in Assert.That (lambda) .Throws.Niente (anche se penso che sia cambiato di recente)
Matt Grande

Risposte:


139

Il tuo unit test fallirà comunque se viene generata un'eccezione: non è necessario inserire un'asserzione speciale.

Questo è uno dei pochi scenari in cui vedrai unit test senza alcuna asserzione: il test fallirà implicitamente se viene sollevata un'eccezione.

Tuttavia, se vuoi davvero scrivere un'asserzione per questo, forse per essere in grado di catturare l'eccezione e segnalare "non aspettavo eccezioni ma ho ottenuto questo ...", puoi farlo:

[Test]
public void TestNoExceptionIsThrownByMethodUnderTest()
{
    var myObject = new MyObject();

    try
    {
        myObject.MethodUnderTest();
    }
    catch (Exception ex)
    {
        Assert.Fail("Expected no exception, but got: " + ex.Message);
    }
}

(quanto sopra è un esempio per NUnit, ma lo stesso vale per MSTest)


Ovviamente non dovresti andare a prendere tali eccezioni perché ciò sia vero.
Servy

7
Un test fallirà solo se viene generata un'eccezione non rilevata. A seconda del codice all'interno dei gestori di eccezioni, gli unit test possono essere superati.
ediblecode

1
È utile per Ms Unittest, quindi non esiste il metodo Assert.DoesNotThrow (() in Unittest.
Başar Kaya

26

In NUnit puoi usare:

Assert.DoesNotThrow(<expression>); 

per affermare che il codice non genera un'eccezione. Anche se il test fallirebbe se viene lanciata un'eccezione anche se non ci fosse Assert attorno ad essa, il valore di questo approccio è che puoi quindi distinguere tra aspettative non soddisfatte e bug nei tuoi test e hai la possibilità di aggiungere un messaggio personalizzato verrà visualizzato nell'output di prova. Un output di test ben formulato può aiutarti a individuare gli errori nel codice che hanno causato il fallimento di un test.

Penso che sia valido aggiungere test per garantire che il codice non generi eccezioni; ad esempio, immagina di convalidare l'input e di dover convertire una stringa in entrata in una stringa lunga. Ci possono essere occasioni in cui la stringa è nulla, e questo è accettabile, quindi vuoi assicurarti che la conversione della stringa non generi un'eccezione. Ci sarà quindi del codice per gestire questa occasione, e se non hai scritto un test per questo ti mancherà la copertura di un importante pezzo di logica.


1
L'esplicito DoesNotThrow è carino. Se sei abituato a vedere Assert. * In un test, potresti pensare che l'altro ragazzo fosse pigro e si fosse dimenticato.
Matt Beckman,

C'è qualche equivalente per questo in vstest o mstest?
Dan Csharpster

1
@DanCsharpster, non credo che ci sia, almeno in MSTest - quando ho avuto bisogno di questa funzionalità in MSTest in passato, ho fatto qualcosa del genere: public class TestBase { //believe me, I don't like this anymore than you do. protected void AssertDoesNotThrow(Action action, string message) { try { action(); } catch (Exception) { Assert.Fail(message); } } }
Clarkeye

@ Clarkeye, è un'idea interessante. Grazie! Si spera che impareranno a copiare meglio NUnit nelle versioni future. Ho anche pensato di scrivere un adattatore tra vstest e NUnit.
Dan Csharpster

@DanCsharpster, una cosa a cui potresti voler dare un'occhiata sono le affermazioni fluide, che hanno un buon supporto per ShouldThrow e ShouldNotThrow: github.com/dennisdoomen/fluentassertions/wiki#exceptions . I documenti dicono che è compatibile con MSTest (anche se l'ho usato solo con XUnit e NUnit). Potrebbe non fare tutto quello che vuoi, ma puoi comunque combinarlo con le affermazioni MSTest.
Clarkeye

12

Non verificare che qualcosa non accada . È come assicurarsi che il codice non si rompa . Questo è un po 'implicito, tutti ci sforziamo per un codice senza interruzioni e senza bug. Vuoi scrivere test per questo? Perché un solo metodo? Non vuoi che tutti i tuoi metodi vengano testati in modo da non generare eccezioni ? Seguendo questa strada, ti ritroverai con un test in più, fittizio e senza asserzioni per ogni metodo nella tua base di codice. Non porta valore.

Naturalmente, se la vostra esigenza è quella di verificare il metodo fa eccezioni di cattura , fate test che (o invertire un po ', prova che esso non buttare ciò che si suppone di cattura).

Tuttavia, l'approccio / le pratiche generali rimangono intatti: non si scrivono test per alcuni requisiti artificiali / vaghi che non rientrano nell'ambito del codice testato (e il test che "funziona" o "non genera" è di solito un esempio di tale - specialmente nello scenario in cui le responsabilità del metodo sono ben note).

Per semplificare, concentrati su ciò che il tuo codice deve fare e prova per questo.


10
-1 Posso pensare a funzionalità positive che richiedono e l'eccezione non deve essere generata. Per prima cosa, il metodo il cui compito è gestire le eccezioni, registrarle e agire - senza lanciare ulteriormente l'eccezione. Fai un buon punto generale, ma poi parla in assoluto come se fosse sempre vero.
Rob Levine

3
@ RobLevine: Capisco il tuo esempio e mi rendo conto che scrivi test in questi casi. Tuttavia, come hai notato, il mio punto in effetti riguardava la pratica più generale - per così dire, testare ciò che il tuo codice dovrebbe fare rispetto a ciò che il tuo codice non fa. Ho riformulato un po 'il mio post, in modo che il mio punto sia più chiaro e più vicino a ciò che avevo in mente. Ti dà anche l'opportunità di riconsiderare il tuo voto. Grazie per il chiarimento e ci scusiamo per il ritardo nella risposta.
km

4
voto negativo rimosso: la prossima volta non sarò così contento del voto negativo!
Rob Levine,

4
Nel nostro progetto abbiamo la classe htmlvalidator, che genera eccezioni se html non è valido. Ad esempio, quando l'utente immette (utilizzando la console) javascript in rich combo. Quindi nel mio caso il codice ciò che il mio codice fa è non lanciare eccezioni (approccio alla lista bianca) e devo testarlo.
Machet

1
Non sono d'accordo con questa risposta. Testare l'assenza di qualcosa a volte in un determinato scenario può essere un test valido.
bytedev

7

Questa classe di aiutanti ha graffiato il mio prurito con MSTest. Forse può graffiare anche il tuo.

[TestMethod]
public void ScheduleItsIneligibilityJob_HasValid_CronSchedule()
{
    // Arrange
    var factory = new StdSchedulerFactory();
    IScheduler scheduler = factory.GetScheduler();

    // Assert
    AssertEx.NoExceptionThrown<FormatException>(() =>
        // Act
        _service.ScheduleJob(scheduler)
    );
}

public sealed class AssertEx
{
    public static void NoExceptionThrown<T>(Action a) where T:Exception
    {
        try
        {
            a();
        }
        catch (T)
        {
            Assert.Fail("Expected no {0} to be thrown", typeof(T).Name);
        }
    }
}

@Remco Beurskens - l'aggiunta di una cattura generale {} alla fine di NoExceptionThrown <T> sopprimerà altri errori, che non è una conseguenza intenzionale del metodo. Questo non è un metodo generico per eliminare tutte le eccezioni. È destinato a fallire solo quando viene generata un'eccezione del tipo noto.
JJS

1
Questo è super vecchio ora, ma Assertha una funzione di accesso alla proprietà singleton, Thatche si può usare come hook per i metodi di estensione. Potrebbe essere più ordinato e più rilevabile da avere Assert.That.DoesNotThrow()piuttosto che AssertEx.DoesNotThrow(). Questa è solo un'opinione.
Richard Hauer

3

Mi piace vedere un Assert.Whateveralla fine di ogni test, solo per coerenza ... senza uno, posso davvero essere sicuro che non dovrebbe essercene uno lì?

Per me, questo è semplice come mettere Assert.IsTrue(true);

Io so che non ho accidentalmente messo quel codice in là, e quindi dovrei essere abbastanza sicuri in uno scremato veloce attraverso che questo era come previsto.

    [TestMethod]
    public void ProjectRejectsGappedVersioningByDefault() {

        var files = new List<ScriptFile>();
        files.Add(ScriptProjectTestMocks.GetVersion1to2());
        files.Add(ScriptProjectTestMocks.GetVersion3to4());

        Assert.Throws<ScriptProject.InvalidProjectFormatException>(() => {
            var sut = new ScriptProject(files);
        });

    }

    [TestMethod]
    public void ProjectAcceptsGappedVersionsExplicitly() {

        var files = new List<ScriptFile>();
        files.Add(ScriptProjectTestMocks.GetVersion1to2());
        files.Add(ScriptProjectTestMocks.GetVersion3to4());

        var sut = new ScriptProject(files, true);

        Assert.IsTrue(true);   // Assert.Pass() would be nicer... build it in if you like

    }

Non è lo stesso. Se il codice viene generato, nessuna affermazione verrà soddisfatta e l'esecuzione di test avrà esito negativo. Vuoi collegarti al framework di test affermando una condizione.
DvS

1

Il mio amico Tim mi ha parlato di ExpectedException . Mi piace molto questo b / c, è più succinto, meno codice e molto esplicito che stai testando un'eccezione.

[TestMethod()]
[ExpectedException(typeof(System.Exception))]
public void DivideTest()
{
    int numerator = 4;
    int denominator = 0;
    int actual = numerator / denominator;
}

Puoi leggere di più a riguardo qui: ExpectedException Attribute Usage .


2
l'OP chiede un'eccezione.
Daniel A. White

Lascio questa risposta qui. Ho trovato questa domanda mentre cercavo su Google come testare le eccezioni e questa risposta penso debba essere qui. L'OP ha avuto risposta alla domanda 7 anni fa. Anche il link all'altra risposta credo sia utile.
Jess,

Buon vecchio Tim. 🤔
ruffin
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.