JustDummies

Juste des dummies, mais redoutablement efficaces.

Sections de la documentation

JustDummies.Xunit

L’adaptateur xUnit v3. Il n’apporte qu’une seule chose — un attribut [Reproducible] — et cette seule chose supprime le besoin d’envelopper le moindre corps de test dans Any.Reproducibly.

Installation

dotnet add package JustDummies.Xunit

Il dépend de JustDummies et de xUnit v3.

Toute la surface

ReproducibleAttribute, avec une propriété Seed assignable. C’est tout — l’adaptateur est volontairement mince, car tout ce dont il a besoin existe déjà dans la bibliothèque (ADR-0018 ouvre un nouvel onglet).

Utilisation

public sealed class OrderTests {

    [Fact, Reproducible]
    public void A_20_percent_discount_takes_a_fifth_off_the_order() {
        // Arrange
        string anyReference = Any.String().StartingWith("ORD-").WithLength(12).Generate();
        string anyCustomer  = Any.String().Alpha().WithLengthBetween(1, 50).Generate();

        Order order = new Order(anyReference, anyCustomer, amount: 100m);

        // Act
        order.ApplyDiscount(20);

        // Assert
        Assert.Equal(80m, order.Total);
    }

}

L’attribut s’applique à trois niveaux, et le plus spécifique l’emporte pendant la durée d’un test :

// Sur une classe : chaque test qu'elle déclare est reproductible.
[Reproducible]
public sealed class OrderTests {

    [Fact]
    public void A_20_percent_discount_takes_a_fifth_off_the_order() {
        // Arrange
        string anyReference = Any.String().StartingWith("ORD-").WithLength(12).Generate();
        string anyCustomer  = Any.String().Alpha().WithLengthBetween(1, 50).Generate();

        Order order = new Order(anyReference, anyCustomer, amount: 100m);

        // Act
        order.ApplyDiscount(20);

        // Assert
        Assert.Equal(80m, order.Total);
    }

    // Sur une méthode, pour rejouer une graine rapportée — le niveau extérieur est restauré ensuite.
    [Fact, Reproducible(Seed = 1743029518)]
    public void A_100_percent_discount_clears_the_order() {
        // Arrange
        string anyReference = Any.String().StartingWith("ORD-").WithLength(12).Generate();
        string anyCustomer  = Any.String().Alpha().WithLengthBetween(1, 50).Generate();

        Order order = new Order(anyReference, anyCustomer, amount: 100m);

        // Act
        order.ApplyDiscount(100);

        // Assert
        Assert.Equal(0m, order.Total);
    }

}

Il s’applique aussi à un assembly entier, forme à privilégier quand la reproductibilité doit être le défaut d’une suite. Placez ceci en tête de n’importe quel fichier du projet de test, avant toute déclaration de namespace ou de type :

[assembly: Reproducible]

Ce qu’il fait, précisément

Avant chaque cas de test, l’attribut ouvre la même portée de graine ambiante qu’utilise Any.Reproducibly, en épinglant une graine fraîche — ou celle que vous avez fixée sur Seed. Après le test, il ferme la portée et, uniquement si le test a échoué, écrit la graine dans la sortie du test :

[JustDummies] These arbitrary values were seeded with 1743029518. Reproduce this run with [Reproducible(Seed = 1743029518)].

Remarquez que le message nomme l’attribut, et non Any.Reproducibly(seed, ...). Un test épinglé depuis l’extérieur de son propre corps ne contient aucun appel de ce genre : le nommer enverrait le lecteur chercher du code qui n’existe pas. L’adaptateur fournit son propre fragment de rejeu via la seconde surcharge d’Any.UseSeed — la raison d’être de cette surcharge (ADR-0017 ouvre un nouvel onglet).

Trois conséquences méritent d’être connues :

  • Une graine par cas de test, si bien que chaque cas d’une [Theory] a la sienne au lieu d’en partager une.
  • Un test vert reste silencieux. La graine est une aide au diagnostic, pas une sortie.
  • Les contextes Any.WithSeed(...) ne sont pas affectés. Ce contexte est isolé par conception et ne tire pas de la source ambiante que cet attribut épingle.

Rejouer un échec

Copiez la graine depuis la sortie du test en échec sur l’attribut, relancez, et les valeurs exactes reviennent. Corrigez le défaut, puis retirez l’épingle — une graine versionnée retransforme un test variable en test à un seul cas.

Ce que les analyzers vous diront

RègleSituation
JD010[Reproducible] sur une méthode que xUnit ne traite pas comme un test — elle n’épingle rien et ressemble exactement à la forme qui marche
JD007une valeur tirée dans le constructeur d’une classe [Reproducible], que xUnit exécute avant l’ouverture de la portée : la graine rapportée ne la rejoue donc pas
JD008le fournisseur de données d’une théorie qui tire à la découverte, avant qu’aucune graine ne soit épinglée

Si vous utilisez xUnit v2

Cet adaptateur ne cible que la v3. En v2, utilisez Any.Reproducibly(() => { ... }) dans le corps du test : vous obtenez la même portée épinglée et le même rapport de graine, au prix d’une lambda d’enveloppe. Voir Reproductibilité.

Lire la source, ou la corriger là-bas ouvre un nouvel onglet· Repris depuis xunit-v1.0.0-preview.2