2017-10-16 79 views
1

我有一个使用.NET Framework 4.6.1和EF6的ASP.NET Core项目。 现在我想编写一些单元测试,并已花费数小时来配置内存SQLite数据库以使用EF6。但它不起作用。使用EF6(Entity Framework 6)编写单元测试

所以,问题是我怎样才能测试我的项目使用EF6没有任何嘲笑(而不是内存数据库)?

我当前的代码:

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

如果我尝试添加一个用户,我获得以下错误:

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

假定我的表是通过调用this.Context.Database.CreateIfNotExists();产生,或我误解了吗?

+0

我知道它不回答你的问题,但你应该考虑https://github.com/tamasflamich/effort – Jim

+0

FWIW,内存数据库还是不行,这不是单元测试;这是一个*集成测试*。在这方面,你真的应该使用你的实际站点运行的同一个数据库平台,例如像SQL Server,而不是SQLite。 –

回答

2

考虑使用NuGet包努力

它是一个简单,快速的内存中用于单元测试数据库。

您可以使用数据库播种器自己填充空数据库来启动它,也可以使用测试CSV文件中的值填充它。

参见通过博客和帖子数据库Tutorials Effort - Entity Framework Unit Testing Tool

简单的例子。博客和帖子之间的一对多关系

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

您不会获得连接字符串,而是获得DbConnection。因此,BloggingContext的第二个构造函数。传递给超类的布尔值是告诉dbcontext它拥有连接,它应该关闭并在DbContext处置时处置连接。

这是您正常的DbContext用法的唯一区别。所有其他对DbContext和DbSets的调用都是正常的。

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

一个提示:在开发时,有时很难看到测试是否失败,因为或者由于不正确的代码的不正确的测试(数据)被测试。在调试期间检查数据库中的内容是非常困难的。因此,我倾向于用充满测试值的真实数据库开发测试,一旦很少需要调试测试,就切换到内存数据库。事实上,对我来说,这是第二个或第三个DbContext构造函数之间的切换

+0

哇,这个简单的代码行你让我!它现在工作:)谢谢! –

相关问题