2017-10-16 8 views
1

J'ai un projet ASP.NET Core utilisant .NET Framework 4.6.1 et EF6. Maintenant, je veux écrire des tests unitaires et j'ai déjà passé des heures à configurer une base de données SQLite en mémoire pour utiliser EF6. Mais ça ne marche pas.Ecriture d'un test unitaire utilisant EF6 (Entity Framework 6)

Donc, la question est comment puis-je tester mon projet en utilisant EF6 sans aucun faux (plutôt une base de données en mémoire)?

Mon code actuel:

public class DataAccessLayer : DbContext 
{ 
    public DataAccessLayer(string connectionString) 
    : base(connectionString) { 
    } 

    public DataAccessLayer(DbConnection connection) 
    : base(connection, true) { 
    } 

    public DbSet<User> Users { get; set; } 

    public DbSet<Setting> Settings { get; set; } 

    public DbSet<UserRole> UserRoles { get; set; } 

    public DbSet<MainKey> MainKeys { get; set; } 
} 

[Table("Users")] 
public class User 
{ 
    [Key] 
    [Required] 
    public int UserID { get; set; } 

    [Required][StringLength(50)] 
    public string UserName { get; set; } 

    ... 
} 

public class Testbase 
{ 
    protected DataAccessLayer Context { get; private set; } 

    [TestInitialize] 
    public virtual void SetUp() 
    { 
    var connection = this.CreateConnection(); 
    connection.Open(); 
    this.Context = new DataAccessLayer(connection); 
    this.Context.Database.CreateIfNotExists(); 
    } 

    private SQLiteConnection CreateConnection() { 
    var connectionStringBuilder = new SQLiteConnectionStringBuilder { DataSource = ":memory:" }; 
    return new SQLiteConnection(connectionStringBuilder.ToString()); 
    } 
} 

Si je tente d'ajouter un utilisateur, je reçois l'erreur suivante:

System.Data.SQLite.SQLiteException: SQL logic error or missing database no such table: Users.

Je suppose que mes tableaux sont générés en appelant this.Context.Database.CreateIfNotExists();, ou est-ce que je me trompe à ce sujet?

+0

Je sais que cela ne répond pas à votre question, mais vous devriez considérer https://github.com/tamasflamich/effort – Jim

+0

FWIW, dans base de données de la mémoire ou non, ce n'est pas un test unitaire; C'est un * test d'intégration *. À cet égard, vous devriez vraiment utiliser la même plate-forme de base de données que votre site actuel, c'est-à-dire quelque chose comme SQL Server, pas SQLite. –

Répondre

2

Tenir compte en utilisant le paquet Nuget Effort

Il est une base de données simple et en mémoire rapide utilisé pour les tests unitaires.

Vous pouvez le démarrer avec une base de données vide et le remplir vous-même à l'aide d'un semoir de base de données, ou vous pouvez le remplir avec des valeurs d'un fichier CSV de test.

Voir Tutorials Effort - Entity Framework Unit Testing Tool

Exemple simple avec une base de données avec les blogs et les messages. Un one-to-many entre les blogs et les messages

public class Blog 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public virtual ICollection<Post> Posts { get; set; } 
} 

public class Post 
{ 
    public int Id { get; set; } 
    public string Title { get; set; } 
    public string Content { get; set; } 

    public int BlogId { get; set; } 
    public virtual Blog Blog { get; set; } 
} 

public class BloggingContext : DbContext 
{ 
    public BloggingContext() : base() { } // constructor using config file 

    public BloggingContext(string nameOrConnectionString) : base(nameOrConnectionString) { } 
    public BloggingContext(DbConnection connection) : base(connection, true) { } 
    public DbSet<Blog> Blogs { get; set; } 
    public DbSet<Post> Posts { get; set; } 
} 

Vous ne recevez pas une chaîne de connexion, au lieu que vous obtenez un DbConnection. D'où le deuxième constructeur pour le BloggingContext. Le booléen transmis à la super classe est de dire au dbcontext qu'il possède la connexion, il doit fermer et éliminer la connexion lorsque le DbContext est éliminé.

C'est la seule différence avec votre utilisation normale de DbContext. Tous les autres appels à DbContext et DbSets sont normaux.

Exemple

static void Main(string[] args) 
{ 
    var connection = Effort.DbConnectionFactory.CreateTransient(); 

    using (var dbContext = new BloggingContext(connection)) 
    { 
     var addedBlog = dbContext.Blogs.Add(new Blog[] 
     { 
      Name = "1", 
      Posts = new Post[] 
      { 
       new Post() {Title = "1st", Content = "a"}, 
       new Post() {Title = "2nd", Content = "b"}, 
       new Post() {Title = "3rd", Content = "c"}, 
      }, 
     }); 
     dbContext.SaveChanges(); 
    } 

    using (var dbContext = new BloggingContext(connection)) 
    { 
     var allPosts = context.Posts.ToList(); 
     foreach (var post in allPosts) 
     { 
      Console.WriteLine($"{post.Id}: {post.Title}"); 
     } 
    } 

Un conseil: tout en développant il est parfois difficile de voir si le test échoue à cause de mauvais critère (données) ou à cause de code incorrect testé. Il est assez difficile de vérifier pendant le débogage ce qui se trouve dans la base de données pendant le test. Par conséquent, j'ai tendance à développer les tests avec une base de données réelle remplie de valeurs de test, et une fois que le débogage des tests est rarement nécessaire, passez à la base de données en mémoire. En fait, pour moi, il s'agit d'un changement entre le deuxième ou le troisième constructeur DbContext

+0

wow avec ces simples lignes de code vous m'avez! Ca marche maintenant :) Merci !! –