使用EF6编写单元测试(实体框架6) [英] Writing unit-test using EF6 (Entity Framework 6)

查看:158
本文介绍了使用EF6编写单元测试(实体框架6)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用.NET Framework 4.6.1和EF6的ASP.NET Core项目。
现在,我想编写一些单元测试,并且已经花费了数小时来配置内存中的SQLite数据库以使用EF6。

I have an ASP.NET Core project using .NET Framework 4.6.1 and EF6. Now I want to write some unit tests and already spent hours to configure an in-memory SQLite database for using EF6. But it doesn't work.

所以,问题是如何在没有任何模拟的情况下(而不是内存数据库)使用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());
  }
}

如果我尝试添加用户,则会得到以下关注错误:

If I try to add a user, I get following error:


System.Data.SQLite.SQLiteException:SQL逻辑错误或缺少数据库
没有这样的表:Users。

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

我假设通过调用 this.Context.Database.CreateIfNotExists生成我的表(); ,还是我误会了?

I assume that my tables are generated by calling this.Context.Database.CreateIfNotExists();, or am I mistaken about that?

推荐答案

考虑使用Nuget包努力

Consider using the Nuget package Effort

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

It is a simple and fast in-memory database used for unit testing.

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

You can start it with an empty database and fill it yourself using a database seeder, or you can fill it with values from a test CSV file.

请参见教程工作量-实体框架单元测试工具

带有博客和帖子的数据库的简单示例。博客与帖子之间的一对多关系

Simple example with a database with Blogs and Posts. A one-to-many relationship between Blogs and Posts

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的第三个构造函数。

You don't get a connection string to a database, instead you get a DbConnection to it. Hence the third constructor for the BloggingContext.

传递给该构造函数的超类的布尔值是告诉DbContext它拥有连接:DbContext应该关闭并处理

The Boolean passed to the super class in this constructor is to tell the DbContext that it owns the connection: the DbContext should close and Dispose the connection when the it is Disposed.

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

This is the only difference with your normal DbContext usage. All other calls to DbContext and DbSets are normal.

示例

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构造函数之间的切换

One tip: while developing it is sometimes difficult to see whether the test fails because of incorrect test (data) or because of incorrect code being tested. It is fairly difficult to check during debugging what is in the database during the test. Hence I tend to develop the tests with a real database filled with test values, and once debugging of the tests is seldom needed, switch to the in-memory database. In fact, for me this is a switch between the second or the third DbContext constructor

这篇关于使用EF6编写单元测试(实体框架6)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆