2008-10-07 7 views
2

L'un de nos tests unitaires consiste à remplir des propriétés au sein de nos objets métier avec des données aléatoires.Obtenir des données aléatoires à l'aide des génériques

Ces propriétés sont de différents types intrinsèques et nous voudrions utiliser la puissance des génériques pour renvoyer des données du type que vous passez quelque chose le long des lignes de:.

public static T GetData<T>() 

Comment feriez-vous approcher cela? Est-ce qu'une interface de bas niveau fonctionnerait? (IConvertible)

Répondre

1

Cela dépend de ce que les données que vous voulez randomiser, parce que la façon ou l'algorithme que vous souhaitez utiliser est totalement différent en fonction du type.

Par exemple:

// Random int 
Random r = new Random(); 
return r.Next(); 

// Random Guid 
return Guid.NewGuid(); 

... 

Cela fait donc évidemment l'utilisation des médicaments génériques sur une belle fin est la simplification de l'utilisateur, mais il ajoute aucune valeur à la façon dont vous écrivez la classe. Vous pouvez utiliser une clause de commutateur ou un dictionnaire (comme Jon Skeet suggère):

switch(typeof(T)) 
{ 
    case System.Int32: 
     Random r = new Random(); 
     return (T)r.Next(); 
    case System.Guid: 
     return (T)Guid.NewGuid(); 
    ... 

Ensuite, vous utilisez la classe que vous attendez:

RandomGenerator.GetData<Guid>(); 
... 
+0

Afin de lancer r.Next() pour taper ce dont T hériterait –

+0

Je suppose que le casting wo Je serais résolu à l'exécution, mais je n'ai pas essayé, sinon vous pouvez doubler la distribution (T) (objet) ... – Sklivvz

+0

Cela a fonctionné à peu près, car la solution que je cherchais était assez simple. Merci –

16

Vous pouvez conserver l'interface GetData "facile à utiliser" que vous avez ici, mais en interne avoir un < Type de dictionnaire, objet> où chaque valeur est un Func < T> pour le type approprié. GetData aurait alors une mise en œuvre tels que:

public static T GetData<T>() 
{ 
    object factory; 
    if (!factories.TryGet(typeof(T), out factory)) 
    { 
     throw new ArgumentException("No factory for type " + typeof(T).Name); 
    } 
    Func<T> factoryFunc = (Func<T>) factory; 
    return factoryFunc(); 
} 

Vous souhaitez ensuite mettre en place le dictionnaire de l'usine dans un initialiseur statique, avec un délégué pour chaque type de données aléatoires que vous voulez créer. Dans certains cas, vous pouvez utiliser une expression lambda simple (par exemple pour les entiers) et, dans certains cas, le délégué peut pointer vers une méthode faisant plus de travail (par exemple pour les chaînes).

Vous voudrez peut-être utiliser ma classe StaticRandom pour RNG threadless, d'ailleurs.

+0

Approche intéressante. J'ai mon vote. – OregonGhost

+0

Merci, je vais essayer et poster mes résultats. –

+0

Juste une question, pourquoi déclarez-vous usine en tant qu'objet au lieu de Func en premier lieu? – OregonGhost

2

En général, j'éviter d'écrire des tests unitaires aléatoires, parce que ce n'est pas le but des tests unitaires. Lors de l'écriture de tests unitaires, vous voulez vraiment générer les données manuellement pour vous assurer que tous les chemins de votre classe/programme sont couverts, et généralement vous coder ces données dans le test, pour permettre de relancer le test.

Donc je suppose que vous écrivez vraiment des tests de fumée, pour voir comment votre logiciel se comporte pour les gros ensembles de données. Ici, je pense que vous devez implémenter un générateur spécifique pour chacun de vos types d'objet métier, comme quelqu'un d'autre l'a déjà suggéré - pour vous assurer que les données sont raisonnablement similaires à celles attendues en production (par exemple pas aléatoire).

0

Je voudrais utiliser AutoPoco pour générer les données nécessaires pour le test.

Questions connexes