55 votes

Test unitaire de DbContext

J'ai recherché quelques informations sur les techniques que je pouvais utiliser de l'unité de test d'un DbContext. Je voudrais ajouter quelques données en mémoire pour le contexte, de sorte que mes tests peuvent être exécutés sur elle. Je suis à l'aide de la Base de données de la Première approche.

Les deux articles que j'ai trouvé les plus utiles ont été ce et ce. Cette approche s'appuie sur la création d'un IContext interface que les deux MyContext et FakeContext mettra en œuvre, permettant de simuler le contexte.

Cependant, j'essaie d'éviter à l'aide de référentiels abstraites de l'EF, comme souligné par certaines personnes, depuis EF 4.1 implémente déjà référentiel et de l'unité de modèles de travail par le biais de DbSet et DbContext, et je tiens vraiment à conserver toutes les fonctionnalités mises en place par l'Équipe EF sans avoir à maintenir moi-même avec un générique référentiel, comme je l'ai déjà fait dans d'autres projets (et c'était un peu douloureux).

Travailler avec un IContext me conduira à le même chemin (ou n'est-ce pas?).

J'ai pensé à la création d'un FakeContext qui hérite de principal MyContext et ainsi profiter de la DbContext dessous pour exécuter mes tests sans frapper, la base de données. Je ne pouvais pas trouver des semblables, alors j'espère que quelqu'un peut m'aider sur ce point.

Suis-je en train de faire quelque chose de mal, ou cela pourrait-il me conduire à certains problèmes que je ne suis pas anticiper?

37voto

Ladislav Mrnka Points 218632

Posez-vous une seule question: Qu'allez-vous tester?

Vous avez mentionné FakeContext et se moquant du contexte - pourquoi utiliser les deux? Ce sont juste des façons différentes de faire la même fournir de tester uniquement la mise en œuvre du cadre.

Il y en a un plus gros problème - semblant ou de se moquer de contexte ou de l'ensemble n'a qu'un seul résultat: Vous n'êtes pas de tester votre code réel plus.

Exemple Simple:

public interface IContext : IDisposable
{
     IDbSet<MyEntity> MyEntities { get; }
}

public class MyEntity
{
    public int Id { get; set; }
    public string Path { get; set; } 
}

public class MyService
{
    private bool MyVerySpecialNetMethod(e)
    {
        return File.Exists(e.Path);
    }

    public IEnumerable<MyEntity> GetMyEntities()
    {
        using (IContext context = CreateContext())
        { 
            return context.MyEntities
                          .Where(e => MyVerySpecialNetMethod(e))
                          .Select(e)
                          .ToList();
        }
    }
}

Maintenant, imaginez que vous avez dans votre SUT (système sous test, - en cas de test de l'unité est une unité = généralement une méthode). Dans le code de test que vous fournissez FakeContext et FakeSet et il fonctionnera - vous aurez un vert de test. Maintenant dans le code de production, vous devrez fournir un autre dérivé DbContext et DbSet et vous obtiendrez une exception à l'exécution.

Pourquoi? Parce qu'en utilisant des FakeContext vous avez aussi changé de fournisseur LINQ et au lieu de LINQ to entities vous exécutez LINQ to Objects donc appel local .NET des méthodes qui ne peuvent être converties en SQL fonctionne ainsi que de nombreux autres LINQ caractéristiques qui ne sont pas disponibles dans LINQ to entities! Il y a d'autres questions que vous pouvez trouver à la modification des données, comme bien d'intégrité référentielle, les suppressions en cascade, etc. C'est la raison pour laquelle je crois que le code traitant de contexte / LINQ to entities devrait être couvert par les tests d'intégration et exécutées sur la base de données réelle.

14voto

tamasf Points 308

Je suis en train d'élaborer un open-source de la bibliothèque afin de résoudre ce problème.

http://effort.codeplex.com

Un petit teaser:

Vous n'avez pas à ajouter de tout code réutilisable, tout simplement appeler les API de la bibliothèque, par exemple:

var context = Effort.ObjectContextFactory.CreateTransient<MyContext>();

Au premier abord cela peut sembler être de la magie, mais les créé ObjectContext objet de communiquer avec une base de données en mémoire et de ne pas parler de l'origine réelle de la base de données. Le terme "transitoire" fait référence au cycle de vie de cette base de données, il ne vit que lors de la présence de la créé objet ObjectContext. Parallèlement créé ObjectContext objets de communiquer avec des instances de base de données, les données ne sont pas partagées à travers eux. Cela permet d'écrire des tests automatisés facilement.

La bibliothèque offre des diverses fonctions à personnaliser la création: partager des données entre les instances, l'ensemble de données initial de la base de données, de créer de faux de la base de données sur les différentes couches de données... découvrez le site du projet pour plus d'info.

11voto

A partir de EF 4.3, vous pouvez tester votre code en injectant un faux DefaultConnectionFactory avant de créer le contexte.

5voto

Josh Gallagher Points 1591

Entity Framework 4.1 est près d'être en mesure d'être moqué dans les tests, mais nécessite un peu d'effort supplémentaire. Le modèle T4 vous offre un DbContext dérivée de la classe qui contient des propriétés DbSet. Les deux choses que je pense que vous devez simuler sont les DbSet objets que ces propriétés retour et de properites et les méthodes que vous utilisez sur le DbContext de la classe dérivée. Les deux peuvent être obtenus en modifiant le modèle T4.

Brent McKendrick a montré les types de modifications qui doivent être apportées à ce poste, mais pas le modèle T4 modifications qui peuvent y arriver. En gros, ce sont:

  1. Convertir le DbSet propriétés sur le DbContext classe dérivée en IDbSet propriétés.
  2. Ajouter une section qui génère une interface pour le DbContext dérivée de la classe contenant la IDbSet propriétés et toutes les autres méthodes (telles que SaveChanges) que vous aurez besoin de se moquer.
  3. Mettre en œuvre la nouvelle interface dans la DbContext de la classe dérivée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X