JustDummies

Juste des dummies, mais redoutablement efficaces.

Sections de la documentation

FAQ

Réponses courtes aux questions les plus fréquentes. Chacune renvoie à la page qui traite le sujet en profondeur.

Choisir la bibliothèque

Est-ce une bibliothèque de test à base de propriétés ?

Non, et la différence mérite d’être claire.

Une bibliothèque à base de propriétés (FsCheck, Hedgehog) exécute votre test de nombreuses fois, sur de nombreuses entrées générées, et rétrécit un échec jusqu’à un contre-exemple minimal. JustDummies tire une valeur par Generate() et ne rétrécit pas. Un échec se récupère en rejouant sa graine, exactement tel qu’il s’est produit.

Les deux résolvent des problèmes différents et cohabitent très bien : le test à base de propriétés explore un espace, JustDummies retire les littéraux dénués de sens des tests par l’exemple ordinaires. Si vous voulez du rétrécissement, prenez une bibliothèque à base de propriétés — celle-ci ne fera pas semblant.

Pourquoi n’y a-t-il pas d’Any.Object<T>() qui remplirait tout un graphe d’objets ?

Parce qu’un générateur qui réfléchit sur votre type doit deviner ce qui rend une instance valide, et il devine faux précisément là où la correction compte — l’invariant que votre constructeur impose, le champ qui doit s’accorder avec un autre champ.

JustDummies vous demande de composer la valeur avec .As(...) et Any.Combine : cela coûte quelques lignes et achète un dummy que votre propre fabrique accepte. Voir Composition, et Principes de conception pour le raisonnement.

Ai-je besoin du paquet JustDummies.Xunit ?

Seulement si vous utilisez xUnit v3 et voulez [Reproducible] plutôt que d’envelopper les corps dans Any.Reproducibly. Tout fonctionne sans lui. Voir sa page.

Valeurs et contraintes

Pourquoi Generate() renvoie-t-il une valeur différente à chaque appel ?

Parce qu’un générateur est une recette, pas une valeur. Any.Int32().Between(1, 100) décrit les entiers acceptables ; chaque Generate() en tire un. Conservez la valeur dans une variable s’il vous faut deux fois la même :

AnyInt32 anyQuantity = Any.Int32().Between(1, 100);

int drawnOnce = anyQuantity.Generate();
int sameValue = drawnOnce;        // le même nombre
int another   = anyQuantity.Generate(); // généralement un autre nombre

Voir Concepts fondamentaux.

Une contrainte doit-elle correspondre à ce que mon test affirme ?

Non — c’est l’unique habitude qui décide si le test vaut quelque chose. Une contrainte énonce un invariant du domaine. Si vous en ajoutez une pour faire passer une assertion, le test prouve désormais que le code est d’accord avec la supposition du test lui-même, et il continuera de passer après un changement de règle.

Mes contraintes ont levé ConflictingAnyConstraintException. Est-ce un bogue ?

Non : c’est la bibliothèque qui refuse une spécification impossible au lieu de boucler ou de renvoyer quelque chose d’arbitraire. Le message nomme les deux contraintes qui se contredisent. Retirez celle des deux qui n’est pas un véritable invariant du domaine. Voir Erreurs et conflits.

Puis-je rendre une valeur optionnelle ?

Oui — .OrNull() produit null environ une fois sur deux, et sinon une valeur contrainte :

int?    discount = Any.Int32().Between(0, 100).OrNull().Generate();
string? note     = Any.String().Alpha().WithLengthBetween(1, 40).OrNull().Generate();

Reproductibilité

Un test a échoué une fois puis est passé à la relance. Que faire ?

Enveloppez le corps dans Any.Reproducibly (ou ajoutez [Reproducible] avec le paquet xUnit) pour que le prochain échec rapporte sa graine. Épinglez ensuite cette graine pour rejouer l’exécution exacte, corrigez le défaut, et retirez l’épingle.

Si l’exécution déjà en échec se trouvait dans une portée reproductible, la graine est dans la sortie d’échec et vous pouvez la rejouer immédiatement. Voir Reproductibilité.

Puis-je obtenir volontairement deux fois les mêmes valeurs ?

Oui, de trois façons, pour trois situations :

// 1. Rejouer tout un corps sous une graine connue.
Any.Reproducibly(1743029518, () => Assert.True(Any.Int32().Positive().Generate() > 0));

// 2. Épingler le contexte ambiant pour un bloc.
using (IDisposable scope = Any.UseSeed(1743029518)) {
    Assert.True(Any.Int32().Positive().Generate() > 0);
}

// 3. Construire un contexte déterministe isolé, hors de tout corps de test.
AnyContext context  = Any.WithSeed(1743029518);
int        quantity = context.Int32().Between(1, 100).Generate();

La séquence des valeurs tirées est-elle stable d’une version à l’autre ?

Au sein d’une version majeure, oui : depuis 1.0.0-preview.1, une graine donnée tire les mêmes valeurs sur chaque version corrective et mineure, garanti par un golden master (ADR-0049 ouvre un nouvel onglet). Une version majeure peut la changer.

Le rejeu survit-il aux tests parallèles ?

Le rejeu vaut par exécution séquentielle. Des tests exécutés en parallèle ont chacun leur portée et se rejouent très bien. Des tâches exécutées en parallèle dans une même portée entrelacent leurs tirages, et cet ordre n’est pas stable — donnez à chaque tâche sa propre portée de graine. Le diagnostic JD022, actif par défaut, le signale.

Plateforme et distribution

Quels types exigent .NET 8 ?

DateOnly, TimeOnly, Int128, UInt128 et Half n’existent pas en deçà de .NET 8 : Any.DateOnly(), Any.TimeOnly(), Any.Int128(), Any.UInt128() et Any.Half() ne figurent donc que sur l’asset net8.0. Tout le reste est disponible partout.

Cela fonctionne-t-il sur .NET Framework ?

Oui. Le plancher supporté est .NET Framework 4.7.2, via l’asset netstandard2.0, et la CI y exécute les suites (ADR-0007 ouvre un nouvel onglet).

Dois-je installer les analyzers séparément ?

Non. Les 33 règles sont embarquées dans le paquet JustDummies lui-même et se mettent à travailler dès la compilation suivante. Le paquet distinct JustDummies.DiagnosticCatalog n’est nécessaire que pour nommer une règle dans un [SuppressMessage] sans littéral de chaîne — voir sa page.

L’API n’est pas encore stable — qu’est-ce que cela implique pour moi ?

La surface publique est déclarée dans PublicAPI.Unshipped.txt, ce qui signifie qu’elle n’est pas figée et qu’une préversion peut la modifier. Le contrat de graine, lui, n’est plus dans ce panier : il est promis depuis 1.0.0-preview.1, comme indiqué plus haut.

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