2017-07-06 2 views
1

J'ai une propriété que je veux tester sur une collection de Stuff, où l'un des Stuff satisfait une certaine propriété. J'ai un moyen de générer un Stuff satisfaisant la propriété, et un moyen de générer un Stuff qui ne le fait pas.Combinaison de deux générateurs à un seul arbitraire dans FsCheck

Aujourd'hui, je fais quelque chose comme ça (oui, j'utilise FsCheck en C#):

IEnumerable<Stuff> GetStuffCollection(int input) 
{ 
    yield return GenerateStuffSatisfyingProperty(input); 
    yield return GenerateStuffNotSatisfyingProperty(input); 
} 

[Fact] 
public void PropertyForCollectionHolds() 
{ 
    Prop.ForAll(Arb.Choose(1,5), input => 
    { 
     var collection = GetStuffCollection(input); 

     return collection.SatisfiesProperty(); 
    }).VerboseCheckThrowOnFailure(); 
} 

mais ce code en dur l'ordre, ce qui Stuff dans la collection qui satisfait la propriété ; J'aimerais aussi arbitrer cela.

Une façon de le faire serait d'imbriquer Prop.ForAll appels; une extérieure qui génère quelque chose qui détermine l'ordre, et un un intérieur qui est celui que j'ai ci-dessus, mais le passage d'un paramètre de contrôle commande au constructeur de collection:

IEnumerable<Stuff> GetStuffCollection(int input, bool first) 
{ 
    if (first) 
    { 
     yield return GenerateStuffSatisfyingProperty(input); 
     yield return GenerateStuffNotSatisfyingProperty(input); 
    } 
    else 
    { 
     yield return GenerateStuffNotSatisfyingProperty(input); 
     yield return GenerateStuffSatisfyingProperty(input); 
    } 
} 

[Fact] 
public void PropertyForCollectionHolds() 
{ 
    Prop.ForAll(Arb.Default.Bool(), first => 
     Prop.ForAll(Arb.Choose(1,5), input => 
     { 
      var collection = GetStuffCollection(input, first); 

      return collection.SatisfiesProperty(); 
     }).VerboseCheckThrowOnFailure() 
    ).VerboseCheckThrowOnFailure(); 
} 

Mais cela se sent klunky et alambiquée. Existe-t-il un moyen plus simple et/ou plus idiomatique de réaliser la même chose, c'est-à-dire de tester le produit cartésien de la sortie de deux bibliothèques arbitraires?

Répondre

0

Vous pouvez utiliser Gen.Shuffle pour générer des séquences dans des ordres différents:

var gen = from input in Gen.Choose(1, 5) 
      let sc = GetStuffCollection(input) 
      from shuffled in Gen.Shuffle(sc) 
      select shuffled 

puis

Prop.ForAll(gen, collection => { ... })