Propriétés de stubbing avec des setters privés pour les tests

10

Nous avons l'objet

public class MyObject{
    protected MyObject(){}

    public string Property1 {get;private set;}
    public string Property2 {get;private set;}
    public string Property3 {get;private set;}
    public string Property4 {get;private set;}
    public string Property5 {get;private set;}
    public string Property6 {get;private set;}
    public string Property7 {get;private set;}
    public string Property8 {get;private set;}
    public string Property9 {get;private set;}
    public string Property10 {get;private set;}
}

Dans notre code de production, nous remplissons cet objet via automapper. Il peut accéder aux propriétés et les définir correctement.

Maintenant, lorsque nous voulons tester cette classe dans un futur pipeline, il n'est pas possible de remplir les propriétés avec des valeurs fictives (à tester).

Il y a quelques options disponibles.

  • Constructeurs personnalisés pour accepter les paramètres requis pour les tests et définir les propriétés, actuellement 3 constructeurs sont requis. Ce n'est pas propre car les constructeurs ne servent aucune fonctionnalité métier.

  • Rendez les propriétés virtuelles afin que la classe puisse être tronquée. Mais marquer les propriétés virtuelles ne fournit aucune valeur commerciale et pollue ma classe.

  • Ajoutez un générateur d'objet à la classe pour construire en interne l'objet. Encore une fois, aucune valeur commerciale ajoutée. Peut-être un peu plus propre mais toujours beaucoup de code non pertinent dans les objets du domaine.

Des suggestions, des conseils ou des options alternatives ici?

JMan
la source

Réponses:

8

Vous disposez d'un certain nombre d'options.

  • Allez-y et utilisez des constructeurs personnalisés, des propriétés virtuelles ou un générateur d'objets. La raison derrière cela est qu'un objet doit se suffire à lui-même et ne pas dépendre d'une magie telle que l'automappeur. Une classe qui est complètement inutile à moins qu'il y ait de la magie n'est pas très bien pensée. La «valeur commerciale» n'est pas le seul déterminant d'une bonne conception.

  • Incluez l'automappeur dans le processus de test. Certains diront que ce n'est plus un test unitaire. Ce n'est pas important. Les tests unitaires ne sont pas le seul type de test.

  • Implémentez quelque chose qui fournit les fonctionnalités de l'automappeur spécifiquement pour les tests. Vous pouvez facilement écrire un petit utilitaire qui utilisera la réflexion pour remplir votre objet à partir d'un dictionnaire contenant les noms et les valeurs des propriétés.

Jetez également un œil à cette question et réponse: préférez-vous faire des trucs privés internes / publics pour les tests, ou utiliser une sorte de hack comme PrivateObject?

Mike Nakis
la source
3

Je n'hésite pas à utiliser la réflexion pour des choses comme celle-ci dans les tests.

Je n'aime pas rendre les choses virtuelles pour se moquer car cela change le code pour une mauvaise raison.

Je ne sais pas automapper mais je suis d'accord avec @Mike que l'inclure dans les tests peut être une bonne idée. Le test de distinction unité / test d'intégration n'est pas très intéressant imo. Bien sûr, si la suite de tests devient grande et lente, vous devrez filtrer et classer les choses pour exécuter uniquement un sous-ensemble sensible de tous les tests à la fréquence la plus élevée.

Exemple de hack en utilisant la réflexion, en utilisant nameof () aura une meilleure performance mais vous perdrez les types .:

public static class TestExtensions
{
    public static void SetProperty<TSource, TProperty>(
        this TSource source,
        Expression<Func<TSource, TProperty>> prop,
        TProperty value)
    {
        var propertyInfo = (PropertyInfo)((MemberExpression)prop.Body).Member;
        propertyInfo.SetValue(source, value);
    }
}
Johan Larsson
la source
0

À des fins de test unitaire, utilisez des cadres de simulation comme Microsoft Fakes, TypeMock et JustMock, qui prennent en charge la simulation des membres privés.

Veuillez également consulter Smocks (packages @nuget disponibles). La limitation des blouses est, elle ne donnera pas accès aux membres privés. Mais il a la capacité de se moquer des membres statiques et non virtuels. Il est également disponible gratuitement.

Une autre façon la plus simple consiste à utiliser PrivateObject / PrivateType.

Karthik V
la source