JustDummies

Juste des dummies, mais redoutablement efficaces.

Sections de la documentation

Énumérations et choix

Quatre générateurs couvrent le cas où la valeur provient d’un ensemble connu plutôt que d’un intervalle : les énumérations, les viviers explicites, les éléments d’une collection existante, et les booléens.

Énumérations

Any.Enum<TEnum>() tire l’un des membres déclarés sur le type :

OrderStatus status    = Any.Enum<OrderStatus>().Generate();
OrderStatus notDraft  = Any.Enum<OrderStatus>().DifferentFrom(OrderStatus.Draft).Generate();
OrderStatus openState = Any.Enum<OrderStatus>().Except(OrderStatus.Shipped, OrderStatus.Cancelled).Generate();
OrderStatus terminal  = Any.Enum<OrderStatus>().OneOf(OrderStatus.Shipped, OrderStatus.Cancelled).Generate();

Le tirage reste à l’intérieur des membres déclarés. Il n’invente jamais de valeur numérique non déclarée, bien que le CLR l’autoriserait — un dummy qui le ferait testerait votre switch contre un état que votre domaine ne possède pas.

Les exclusions qui vident l’univers sont refusées nommément, et l’analyzer JD017 signale les cas constants dès la compilation.

Énumérations de drapeaux

Pour une énumération [Flags], un tirage ordinaire produit toujours un membre déclaré. Élargir ce tirage se demande explicitement :

// Un membre déclaré : None, Read, Write ou Delete.
Permissions single = Any.Enum<Permissions>().Generate();

// N'importe quelle combinaison : Read | Delete, Read | Write | Delete, ...
Permissions combined = Any.Enum<Permissions>().AllowingCombinations().Generate();

// L'une des deux combinaisons que vous nommez : une liste blanche est le vivier, rien à activer.
Permissions writable = Any.Enum<Permissions>()
                          .OneOf(Permissions.Read | Permissions.Write, Permissions.Write | Permissions.Delete)
                          .Generate();

Ce caractère explicite est délibéré (ADR-0020 ouvre un nouvel onglet). Un attribut [Flags] dit que les membres peuvent se combiner, non que toute valeur de votre domaine le fait ; et un générateur qui combinerait automatiquement changerait silencieusement ce que tirent les tests existants le jour où quelqu’un ajoute l’attribut. Demander les combinaisons tient en un appel, et cet appel dit sur place que les combinaisons font partie de ce que ce test couvre.

Ce que cette demande explicite tranche, c’est ce que parcourt un tirage ordinaire, et rien d’autre : nommer une combinaison dans OneOf ne demande rien de tel, puisqu’une liste blanche est le vivier lui-même et qu’y écrire Read | Write revient à demander cette valeur exacte. Une valeur qu’aucun OU de membres déclarés ne produit — (Permissions)16 sur l’énumération ci-dessus — est refusée dans les deux cas, et signalée par JD017.

Viviers explicites

Any.OneOf tire uniformément parmi les valeurs que vous listez :

string  currency = Any.OneOf("EUR", "USD", "GBP").Generate();
int     httpPort = Any.OneOf(80, 443, 8080).Generate();
decimal vatRate  = Any.OneOf(0.055m, 0.10m, 0.20m).Generate();

// Un vivier se restreint comme le reste.
string notEuro = Any.OneOf("EUR", "USD", "GBP").DifferentFrom("EUR").Generate();

Deux erreurs sont assez fréquentes pour avoir leur propre diagnostic.

Lister deux fois la même constante fusionne le doublon : le vivier est plus petit qu’il n’y paraît, et la valeur répétée ne pèse rien de plus — JD025.

Passer des générateurs au lieu de valeurs déduit un vivier de recettes : le tirage renvoie alors un générateur et non une valeur — JD012. Utilisez Any.Combine si vous vouliez composer.

Éléments d’une collection existante

Any.OneOf prend un params T[] : lui passer un tableau s’étend donc normalement et fait ce que vous attendez. Lui passer toute autre collection, non : T se lie au type de la collection elle-même, et le vivier se réduit à un seul élément — cette collection :

List<string> currencies = ["EUR", "USD", "GBP"];

// JD013 : un vivier d'un seul élément, qui est la liste.
IAny<List<string>> wrong = Any.OneOf(currencies);

Any.ElementOf est celui qui tire dans la collection, quel qu’en soit le type :

List<string> currencies = ["EUR", "USD", "GBP"];

string currency = Any.ElementOf(currencies).Generate();

Deux surcharges existent, pour IReadOnlyList<T> et IEnumerable<T>. Le compilateur choisit la plus spécifique dès que le type le permet, car une liste s’indexe tandis qu’une séquence générale doit être parcourue ; les deux sont supportées pour qu’une méthode utilitaire à yield ou une requête LINQ fonctionne sans .ToList() sur le site d’appel.

List<OrderStatus>       open      = [OrderStatus.Draft, OrderStatus.Submitted];
IEnumerable<OrderStatus> lazyOpen = open.Where(status => status != OrderStatus.Draft);

OrderStatus fromList     = Any.ElementOf(open).Generate();
OrderStatus fromSequence = Any.ElementOf(lazyOpen).Generate();

Un vivier vide n’admet aucune valeur et est refusé, plutôt que de renvoyer une valeur par défaut.

Booléens

bool flag       = Any.Boolean().Generate();
bool always     = Any.Boolean().True().Generate();
bool never      = Any.Boolean().False().Generate();
bool notTheSame = Any.Boolean().DifferentFrom(true).Generate();

True() et False() existent pour qu’un site d’appel qui fige le drapeau se lise comme ceux qui ne le figent pas, ce qui compte dans un test où trois dummies sur quatre varient et un seul non.

Any.Boolean().Except(true, false) viderait le domaine, et est refusé avec un message disant exactement cela.

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