FsCheck utilise sprintf "%A"
pour convertir les paramètres de test en chaînes dans la sortie de test, donc ce que vous devez faire est de contrôler la manière dont les types sont mis en forme par le formatter %A
. Selon How do I customize output of a custom type using printf?, la façon de le faire est avec le StructuredFormatDisplay
attribute. La valeur de cet attribut doit être une chaîne au format PreText {PropertyName} PostText
, où PropertyName
devrait être une propriété (pas une fonction!) Sur votre type. Par exemple, disons que vous avez une structure arborescente avec des informations compliquées dans les feuilles, mais pour vos tests, vous n'avez besoin que de connaître le nombre de feuilles, et non leur contenu. Donc, vous commencez avec un type de données comme celui-ci:
// Example 1
type ComplicatedRecord = { ... }
type Tree =
| Leaf of ComplicatedRecord
| Node of Tree list
with
member x.LeafCount =
match x with
| Leaf _ -> 1
| Node leaves -> leaves |> List.sumBy (fun x -> x.LeafCount)
override x.ToString() =
// For test output, we don't care about leaf data, just count
match x with
| Leaf -> "Tree with a total of 1 leaf"
| Node -> sprintf "Tree with a total of %d leaves" x.LeafCount
Maintenant, ce n'est pas ce que vous voulez. pas a déclaré un format personnalisé %A
déclaré, donc FsCheck (et toute autre chose qui utilise sprintf "%A"
pour le formater) finira par sortir toute la structure compliquée de l'arbre et toutes ses données de feuilles non pertinentes au test. Pour que FsCheck produise ce que vous voulez voir, vous devez configurer une propriété , pas une fonction (ToString
ne fonctionnera pas à cette fin) qui affichera ce que vous voulez voir. .: par exemple
// Example 2
type ComplicatedRecord = { ... }
[<StructuredFormatDisplay("{LeafCountAsString}")>]
type Tree =
| Leaf of ComplicatedRecord
| Node of Tree list
with
member x.LeafCount =
match x with
| Leaf _ -> 1
| Node leaves -> leaves |> List.sumBy (fun x -> x.LeafCount)
member x.LeafCountAsString = x.ToString()
override x.ToString() =
// For test output, we don't care about leaf data, just count
match x with
| Leaf -> "Tree with a total of 1 leaf"
| Node -> sprintf "Tree with a total of %d leaves" x.LeafCount
NOTE: Je n'ai pas testé en F #, juste tapé dans la zone de commentaire Stack Overflow - il est donc possible que j'ai foiré la partie ToString()
. (Je ne me souviens pas, et ne peux pas trouver avec un rapide Google, si les remplacements doivent être après ou avant le mot-clé with
). Mais je sais que l'attribut StructuredFormatDisplay
est ce que vous voulez, parce que je l'ai utilisé moi-même pour obtenir une sortie personnalisée de FsCheck. Par ailleurs, vous pouvez également avoir défini un attribut StructuredFormatDisplay
sur le type d'enregistrement compliqué dans mon exemple. Par ailleurs, vous pouvez également définir un attribut StructuredFormatDisplay
.Par exemple, si vous avez un test où vous vous souciez de la structure de l'arbre, mais pas sur le contenu des feuilles, vous rédigeriez comme:
// Example 3
[<StructuredFormatDisplay("LeafRecord")>] // Note no {} and no property
type ComplicatedRecord = { ... }
type Tree =
| Leaf of ComplicatedRecord
| Node of Tree list
with
member x.LeafCount =
match x with
| Leaf _ -> 1
| Node leaves -> leaves |> List.sumBy (fun x -> x.LeafCount)
override x.ToString() =
// For test output, we don't care about leaf data, just count
match x with
| Leaf -> "Tree with a total of 1 leaf"
| Node -> sprintf "Tree with a total of %d leaves" x.LeafCount
Maintenant, tous vos ComplicatedRecord
cas, peu importe leur contenu, sera apparaît comme le texte LeafRecord
dans votre sortie, et vous serez mieux en mesure de vous concentrer sur la structure arborescente - et il n'était pas nécessaire de définir un attribut StructuredFormatDisplay
sur le type Tree
.
Cette solution n'est pas idéale, car vous devrez peut-être ajuster l'attribut StructuredFormatDisplay
de temps à autre, selon les besoins des différents tests que vous exécutez. (Pour certains tests, vous pouvez vous concentrer sur une partie des données de feuille, pour d'autres, vous voulez ignorer complètement les données de feuille, etc.). Et vous voudrez probablement retirer l'attribut avant de passer à la production. Mais jusqu'à ce que FsCheck acquière une fonction «Donnez-moi une fonction pour mettre en forme les données de test ayant échoué avec le paramètre« config », c'est le meilleur moyen de mettre vos données de test au format dont vous avez besoin.
Comment allez-vous vos affirmations? Il y a différentes manières d'affirmer même en utilisant NUnit pour exécuter des tests. Cela aiderait à fournir un exemple de test, ou même la dernière ligne. – TheQuickBrownFox
Je viens d'ajouter un exemple de code. Le plus difficile était de faire fonctionner le générateur. Pour la propriété elle-même, je reçois une entrée aléatoire, appelle la méthode testée avec cette entrée et renvoie un booléen (le résultat de la comparaison dans ce cas). –
Est-ce que 'Graph <_,_>' un enregistrement ou une classe? Pouvez-vous fournir la définition (peut-être épurée) pour cela? Et la sortie réelle que vous voyez? – TheQuickBrownFox