Question Voies de couche d'accès aux données de test unitaire


J'essaie de trouver un moyen efficace de tester l'unité de ma couche d'accès aux données en C #. Je suis un développeur Java primaire et je n'ai utilisé C # que pendant environ 6 mois. Par le passé, j'ai utilisé une bibliothèque appelée DBUnit pour tester une base de données d'état connue. Je n'ai pas été en mesure de trouver une bibliothèque active similaire pouvant être utilisée, la plus proche semble être nDBUnit mais elle n'est pas active depuis un certain temps maintenant.

Il semble y avoir beaucoup de méthodes contradictoires sur comment et pourquoi en C #. Idéalement, je souhaite tester la couche d'accès aux données à l'aide de moqueries sans avoir besoin de me connecter à une base de données, puis tester l'unité de la procédure de stockage dans un ensemble de tests distinct.

Dans le système sur lequel je travaille, la couche d'accès aux données doit utiliser ADO.net (sans utiliser Entity Framework) pour appeler les procédures de stockage sur un serveur SQL.

Vous trouverez ci-dessous un exemple de code avec lequel je dois travailler; Pour suivre le chemin moqueur, il faudrait que je sois capable de simuler SqlCommand (en utilisant IDbCommand) et / ou de simuler SqlConnection.

Donc, ma question est la suivante: qu'est-ce qui semble être le meilleur moyen (s'il y a une telle chose) de faire cela? Jusqu'à présent, le seul moyen serait de créer un objet proxy transmis au constructeur afin qu'il puisse renvoyer les objets Sql * simulés pour les tests.

Je n'ai pas eu la chance de regarder toutes les librairies C # disponibles pour le moment.

public class CustomerRepository : ICustomerRepository
{
   private string connectionString;

   public CustomerRepository (string connectionString)
   {
     this.connectionString = connectionString;
   }

   public int Create(Customer customer)
   {

     SqlParameter paramOutId = new SqlParameter("@out_id", SqlDbType.Int);
     paramOutId.Direction = ParameterDirection.Output;
     List<SqlParameter> sqlParams = new List<SqlParameter>()
     {
       paramOutId,
       new SqlParameter("@name", customer.Name)
     }

     SqlConnection connection = GetConnection();
     try
     {
       SqlCommand command = new SqlCommand("store_proc_name", connection);

       command.CommandType = CommandType.StoredProcedure;

       command.Parameters.AddRange(sqlParams.ToArray());

       int results = command.ExecuteNonQuery();

       return (int) paramOutId.Value;
     }
     finally
     {
       CloseConnection(connection);
     }

   }

}

16
2018-02-21 11:18


origine


Réponses:


Il est malheureux que vous ne puissiez pas trouver un outil qui place votre base de données dans un état connu et vous permet d'exécuter votre CustomerRepository sur la base de données pour tester le CustomerRepository. Cependant, la réponse n'est pas de commencer à utiliser des simulacres pour simuler tous les appels ADO. En faisant cela, vous finissez par créer un test unitaire qui ne teste pas vraiment de logique: il suffit de tester que le code est écrit comme vous le pensez.

Disons que je finis par écrire un SQL INSERT comme commande pour créer le client dans la base de données SQL. Maintenant, disons que nous apportons une modification pour que la table client ait des champs différents (ce qui casse notre commande INSERT) et que maintenant nous devrions utiliser une procédure stockée pour créer le client. Le test avec des simulacres passerait quand même, même si l'implémentation testée est maintenant interrompue. De plus, si vous corrigiez l'implémentation pour utiliser des procédures stockées, vos tests unitaires échoueraient désormais. Quel est le but d'un test unitaire s'il continue à passer alors qu'il devrait échouer mais échouerait alors lorsque vous avez corrigé le système?

Voir cette question pour quelques alternatives possibles. Il semble que la réponse marquée consiste à utiliser DBUnit en C # avec IKVM.

Donc, il pourrait y avoir des solutions alternatives à continuer à explorer, mais se moquer des appels d'ADO va simplement conduire à des tests fragiles qui ne testent pas vraiment quelque chose d'important.


19
2018-02-24 06:40



Le travail de cette couche consiste à connecter le code à la base de données. Il doit encapsuler les connaissances sur la connexion et la syntaxe de la base de données. In mappe généralement la langue du domaine au langage de base de données. Je considère cette partie des tests unitaires comme un test d’intégration et, en tant que tel, je vérifie que le schéma de base de données est équivalent à une base de données réelle ou de test. Plus sur le sujet ici.


2
2018-02-24 05:15



Je commence par obtenir un IDbConnection alors vous pouvez essentiellement faire le reste de votre code à partir de cela.

using(IDbConnection conn = factory.GetConnection(connectionstring))
{
    conn.Open();
    using(IDbTransaction trans = conn.BeginTransaction())
    {
        IDbCommand command = conn.CreateCommand();
        IDataParameter param = command.CreateParameter();
        // Do something with your command
        trans.Commit();
    }
}

Vous pouvez ensuite simuler la fabrique, l'IDbConnection, l'IDBTransaction et tout autre objet ADO que vous créez à partir de ceux-ci. En ce qui concerne une bibliothèque fictive, j'utilise Moq.


1
2018-02-21 11:38



Pour tester DataAccess Layer, vous aurez besoin d'une structure plus complexe.

DataAccess Layer appelle les références des objets du référentiel. L'objet Repo appelle les références d'Entity Framework DbSets via le motif de conception UnitOfWork.

DataAccess Layer (TOP)
|
UnitOfWork
|
Classes de modèles de référentiels
|
Contexte EF
|
Base de données réelle

Une fois la structure définie, vous simulerez les classes de référentiel. Par exemple, les éléments seront insérés dans DB au lieu de cela iront à l'objet de simulation. Plus tard, vous affirmerez que votre objet est invisible ou non.

S'il vous plaît jeter un oeil à Implémentation du référentiel et des modèles d'unité de travail


0
2018-06-06 14:31