Moyens de tests unitaires couche d'accès aux données
je dois essayer de trouver un moyen efficace dans l'Unité de tester ma couche d'accès aux données dans C#. Je suis principalement un développeur Java et n'ai utilisé C# que depuis environ 6 mois, dans le passé j'ai utilisé une bibliothèque appelée DBUnit pour tester contre une base de données d'état connue. Je n'ai pas été en mesure de trouver une bibliothèque active similaire qui peut être utilisé, le plus proche semble être nDBUnit, mais il n'a pas été actif depuis un certain temps maintenant.
il semble y avoir beaucoup de méthodes contradictoires sur comment et pourquoi dans C#. Idéalement, je veux pour tester la couche d'accès aux données en utilisant mocking sans la nécessité de se connecter à une base de données et ensuite unité tester la procédure de stockage dans un ensemble séparé de tests.
dans le système sur lequel je travaille, la couche d'accès aux données est à utiliser ADO.net (sans L'utilisation du framework Entity) pour appeler des procédures de stockage sur un serveur SQL.
ci-dessous est un exemple de code de ce que je dois travailler avec; pour descendre le chemin moqueur, je devrais être en mesure de moquer le SqlCommand (en utilisant IDbCommand) et / ou maquette de l'occurrence de SqlConnection.
ma question est donc de savoir quelle est la meilleure façon (s'il y a une telle chose) de faire cela? Jusqu'à présent la seule façon serait de faire un objet Proxy qui est passé dans le constructeur pour qu'il puisse retourner les objets SQL* moqués pour les tester.
Je n'ai pas encore eu la chance de regarder toutes les bibliothèques disponibles c# mock.
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);
}
}
}
4 réponses
il est malheureux que vous ne pouvez pas trouver un outil qui met votre base de données dans un état connu et vous permet d'exécuter votre CustomerRepository contre la base de données pour tester le CustomerRepository. Cependant, la réponse n'est pas de commencer à utiliser des moqueries pour se moquer de tous les appels ADO. En faisant cela, vous finissez par créer un test unitaire qui ne teste vraiment aucune logique: c'est juste tester que le code est écrit de la façon dont vous pensez qu'il devrait être écrit.
disons que je finis par écrire un SQL Insérez comme ma commande pour créer le client dans la base de données SQL. Maintenant, disons que nous faisons un changement de sorte que la table de client a différents champs (qui casse notre commande INSERT) et que maintenant nous devrions utiliser une procédure stockée pour créer le client. Le test avec mocks serait quand même réussi, même si l'implémentation qu'il est en train de tester est maintenant cassée. De plus, si vous avez corrigé l'implémentation pour utiliser des procédures stockées, vos tests unitaires vont maintenant échouer. Quel est le but d'un test unitaire si il continue à passer quand il devrait échouer, mais alors échouerait quand vous avez corrigé le système?
Voir cette question pour quelques alternatives possibles. Il semble que la réponse marquée est de finir par utiliser DBUnit dans C# en utilisant IKVM.
donc, il y a peut-être d'autres avenues à explorer, mais se moquer des appels ADO ne fera que mener à des tests fragiles qui ne testeront pas vraiment quelque chose d'important.
le travail de cette couche est de connecter le code à la base de données. Il doit encapsuler les connaissances sur la connexion db et la syntaxe. Dans les cartes habituellement le langage de 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 teste que le schéma de la base de données est équivalent par rapport à la base de données réelle ou test. Plus sur le sujet ici.
je commence par obtenir un IDbConnection
vous pouvez vous faire le reste de votre code.
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 alors vous moquer de l'usine, de la connexion IDB, de la transaction IDB, et de tous les autres objets ADO que vous créez à partir de ceux-ci. Comme pour une bibliothèque simulée j'utilise Moq
.
pour tester la couche DataAccess, vous aurez besoin d'une structure plus complexe.
la couche DataAccess appellera les références des objets du dépôt. L'objet Repo appellera des références à partir de DbSets Entity Framework via UnitOfWork design pattern.
couche DataAccess (haut)
/
UnitOfWork
/
Classes De Modèles De Dépôt
/
Contexte EF
/
Réel La base de données
après avoir défini la structure, vous simulerez les classes du dépôt. Par exemple, les éléments seront insérés dans DB à la place ira à l'objet mock. Plus tard, vous vous opposerez à votre objet simulé pour voir l'article inséré ou non.
s'il vous Plaît prendre un coup d'oeil à mise en oeuvre du référentiel et de L'Unité des régimes de travail