2017-10-16 3 views
1

Ich habe ein ASP.NET Core-Projekt mit .NET Framework 4.6.1 und EF6. Nun möchte ich einige Komponententests schreiben und habe bereits Stunden damit verbracht, eine SQLite-In-Memory-Datenbank für die Verwendung von EF6 zu konfigurieren. Aber es funktioniert nicht.Schreibgerät-Test mit EF6 (Entity Framework 6)

Also, die Frage ist Wie kann ich mein Projekt mit EF6 ohne irgendwelche Mocks (eher eine In-Memory-Datenbank) testen?

Mein aktueller Code:

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()); 
    } 
} 

Wenn ich versuche, einen Benutzer hinzufügen, bekomme ich folgende Fehlermeldung:

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

ich nehmen , dass meine Tabellen durch den Aufruf this.Context.Database.CreateIfNotExists(); erzeugt werden, oder Täusche ich mich darüber?

+0

Ich weiß, dass es Ihre Frage nicht beantwortet, aber Sie sollten https://github.com/tamasflamich/effort denken – Jim

+0

FWIW, in- Speicherdatenbank oder nein, dies ist kein Unit-Test; Es ist ein * Integrationstest *. In dieser Hinsicht sollten Sie wirklich die gleiche DB-Plattform verwenden, auf der Ihre tatsächliche Site läuft, d. H. So etwas wie SQL Server und nicht SQLite. –

Antwort

2

Betrachten Sie die Nuget Paket Effort

Es ist eine einfache und schnelle In-Memory-Datenbank verwendet für Unit-Tests verwenden.

Sie können es mit einer leeren Datenbank starten und es mit einem Datenbank-Seeder selbst füllen, oder Sie können es mit Werten aus einer Test-CSV-Datei füllen.

Siehe Tutorials Effort - Entity Framework Unit Testing Tool

Einfaches Beispiel mit einer Datenbank mit Blogs und Beiträgen. Eine Eins-zu-viele-Beziehung zwischen Blogs und Beiträge

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; } 
} 

Sie erhalten nicht eine Verbindungszeichenfolge, stattdessen erhalten Sie einen DbConnection. Daher der zweite Konstruktor für den BloggingContext. Der Boolesche Wert, der an die Superklasse übergeben wird, teilt dem dbcontext mit, dass er die Verbindung besitzt. Er sollte die Verbindung schließen und entsorgen, wenn der DbContext Disposed ist.

Dies ist der einzige Unterschied zu Ihrer normalen DbContext-Verwendung. Alle anderen Aufrufe von DbContext und DbSets sind normal.

Beispiel

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}"); 
     } 
    } 

Ein Tipp: getestet, während es die Entwicklung manchmal schwer zu erkennen, ob der Test wegen falschen Test (Daten) oder wegen falschen Code fehlschlägt. Es ist ziemlich schwierig, während des Debuggens zu überprüfen, was sich während des Tests in der Datenbank befindet. Daher tendiere ich dazu, die Tests mit einer realen Datenbank zu entwickeln, die mit Testwerten gefüllt ist. Sobald das Debuggen der Tests selten erforderlich ist, wechseln Sie in die In-Memory-Datenbank. In der Tat, für mich ist dies ein Wechsel zwischen dem zweiten oder dritten DbContext-Konstruktor

+0

Wow mit diesen einfachen Zeilen Code hast du mich! Es funktioniert jetzt :) Danke !! –

Verwandte Themen