web-dev-qa-db-fra.com

NUnit 3.0 et Assert.Throws

J'écris des tests unitaires avec NUnit 3.0 et, contrairement à la version 2.x, ExpectedException() a été supprimé de la bibliothèque.

Sur la base de this answer, je peux vraiment voir la logique d'essayer de déterminer précisément où, dans le test, on s'attend à ce que leur système lève une exception (plutôt que de simplement dire "n'importe où dans le test").

Cependant, j'ai tendance à être très explicite sur mes étapes Arrange, Act et Assert, ce qui en fait un défi.

Je faisais quelque chose comme:

[Test, ExpectedException(typeof(FormatException))]
public void Should_not_convert_from_prinergy_date_time_sample1()
{
    //Arrange
    string testDate = "20121123120122";

    //Act
    testDate.FromPrinergyDateTime();

    //Assert
    Assert.Fail("FromPrinergyDateTime should throw an exception parsing invalid input.");
}

Maintenant, je dois faire quelque chose comme:

[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
    //Arrange
    string testDate = "20121123120122";

    //Act/Assert
    Assert.Throws<FormatException>(() => testDate.FromPrinergyDateTime());
}

Ce n'est pas terrible, mais confond la Loi et Assert, à mon avis. (Évidemment, pour ce test simple, ce n'est pas difficile à suivre, mais pourrait être plus difficile dans les tests plus importants).

Un collègue m'a suggéré de me débarrasser de Assert.Throws tout à fait et juste faire quelque chose comme:

[Test]
public void Should_not_convert_from_prinergy_date_time_sample3()
{
    //Arrange
    int exceptions = 0;
    string testDate = "20121123120122";

    //Act
    try
    {
        testDate.FromPrinergyDateTime();
    }
    catch (FormatException) { exceptions++;}

    //Assert
    Assert.AreEqual(1, exceptions);
}

Ici, je reste fidèle au format AAA strict, mais au détriment d’en encore plus.

Ma question s'adresse donc aux testeurs de type AAA: comment feriez-vous une sorte de test de validation des exceptions comme j'essaie de le faire ici?

62
Killnine

Je vois d'où vous venez, même si cela ne me dérange pas de combiner les étapes Act/Assert dans ce cas.

La seule chose à laquelle je peux penser est de stocker le délégué réel (ici pour FromPrinergyDateTime) dans une variable en tant qu’étape "act", puis l’affirmer:

[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
    //Arrange
    string testDate = "20121123120122";

    //Act
    ActualValueDelegate<object> testDelegate = () => testDate.FromPrinergyDateTime();

    //Assert
    Assert.That(testDelegate, Throws.TypeOf<FormatException>());
}

Je comprends que l'étape "acte" n'agit pas vraiment, mais définit plutôt ce qu'est l'action. Cependant, il indique clairement quelle action est testée.

61
Patrick Quirk

En C # 7, il existe une autre option (bien que très similaire aux réponses existantes):

[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
    void CheckFunction()
    {
        //Arrange
        string testDate = "20121123120122";

        //Act
        testDate.FromPrinergyDateTime();
    }

    //Assert
    Assert.Throws(typeof(Exception), CheckFunction);
}

blog sur le sujet

22
Paul Michaels

Vous pouvez créer un attribut personnalisé dans NUnit 3. Voici l'exemple de code permettant de créer un attribut [ExpectedException]. (ExpectedExceptionExample montre comment implémenter un attribut personnalisé pour NUnit) https://github.com/nunit/nunit -csharp-samples

6
Matt Allen