简体   繁体   English

使用fixture测试实体框架

[英]Testing Entity Framework with fixtures

One of the things I like about Rails' and Django's testing approach is their support of using fixtures to set up a database before each test is run. 我喜欢RailsDjango测试方法的一个原因是他们支持在每次测试运行之前使用fixture来设置数据库。

In the past, I've used strict unit tests in conjunction with a mocked repository to test my code, but I'd love to have something that's as easy to use as the aforementioned testing approaches in order to do integrated testing. 在过去,我使用严格的单元测试和模拟的存储库来测试我的代码,但是我希望有一些像上述测试方法一样易于使用的东西来进行集成测试。

I've heard some talk of this type of support with code-first and EF 5, but I don't know if it rises to the level of what Rails and Django provide. 我听过一些关于代码优先和EF 5这种支持的讨论,但我不知道它是否升级到Rails和Django提供的水平。

Surely there's something comparable out there. 当然有可比的东西。 Any information would be appreciated! 任何信息,将不胜感激!

In EF5 new concept has been introduced, called Migrations . 在EF5中引入了新概念,称为迁移 You probably used to use something similar in Rails or Django applications. 您可能曾经习惯在Rails或Django应用程序中使用类似的东西。

Migration is a class, that has several functions to upgrade / downgrade the version of DB. 迁移是一个类,它具有多个升级/降级DB版本的功能。

public partial class VoteTime : DbMigration
{
    public override void Up()
    {
        AddColumn("Votes", "Time", c => c.DateTime(nullable:false, defaultValue:DateTime.UtcNow));
    }

    public override void Down()
    {
        DropColumn("Votes", "Time");
    }
}

You also, have to setup DbContext and DbMigrationsConfiguration configuration classes to allow code first approach to work. 您还必须设置DbContext和DbMigrationsConfiguration配置类,以允许代码第一种方法工作。

For testing purposes you need to introduce, TestDatabaseInitilizer 出于测试目的,您需要引入TestDatabaseInitilizer

public class TestDatabaseInitilizer : DropCreateDatabaseAlways<DbContext>
{

}

It would be responsible for initialization of test database for unit tests. 它将负责初始化测试数据库以进行单元测试。

Finally, you should design your test code to setup the context. 最后,您应该设计测试代码来设置上下文。

public class SomeRepositoryTests
{
    private DbContext _context;

    [SetUp]
    public void Setup()
    {
        Database.SetInitializer(new TestDatabaseInitilizer());
        _context = new DbContext("TestContext");
        _repository = new SomeRepository(_context);
    }

    [Test]
    public void should_return_some_entities()
    {
        Assert.That(_repository.Get(), Is.Not.Null);
    }
}

The setup code could be moved to base class, if required. 如果需要,可以将设置代码移动到基类。

I've developed an application with Entity Framework that has over 600 automated integration tests. 我开发了一个带有Entity Framework的应用程序,它有600多个自动集成测试。 This is the process I used: 这是我使用的过程:

  • Entity Framework code first migrations just to set the database structure (tables, indexes, etc.). 实体框架代码首先迁移只是为了设置数据库结构(表,索引等)。 I don't use migrations to seed data. 我不使用迁移来播种数据。

  • SQL scripts that set the database in specific, well-known states. SQL脚本,用于将数据库设置为特定的,众所周知的状态。 For instance, one script to insert ASP.NET membership users; 例如,一个用于插入ASP.NET成员资格用户的脚本; another that sets sample data for the most relevant tables; 另一个为最相关的表设置样本数据; and others for more specific scenarios. 和其他更具体的场景。 The scripts typically delete the records from the appropriate tables and insert them again, in the appropriate order to avoid relationship conflicts. 脚本通常会从相应的表中删除记录,并以适当的顺序再次插入它们,以避免关系冲突。 The scripts are included in the Visual Studio project as embedded resources. 这些脚本作为嵌入式资源包含在Visual Studio项目中。

  • A helper class that can get a script from the resources by its name and execute it against the database, including batching commands with "GO". 一个辅助类,可以通过名称从资源获取脚本并对数据库执行,包括使用“GO”批处理命令。 ConnectionContext.ExecuteNonQuery can be used for that. ConnectionContext.ExecuteNonQuery可以用于此。

  • At the start of the whole test suite, I execute the script that sets up users, permissions and other very general environment configurations. 在整个测试套件的开头,我执行设置用户,权限和其他非常一般环境配置的脚本。

  • Before each test method, I execute one or more scripts, as appropriate, to set the database in the context required by the tests being run. 在每个测试方法之前,我会根据需要执行一个或多个脚本,以便在正在运行的测试所需的上下文中设置数据库。 For instance, before a series of CRUD tests that read, insert, update and delete data, I run a script that seeds the appropriate table with test data. 例如,在读取,插入,更新和删除数据的一系列CRUD测试之前,我运行一个脚本,用适当的表为测试数据播种。

  • I write the test cases assuming the database is set in a specific context. 假设数据库是在特定上下文中设置的,我编写测试用例。 For instance, a test of an update operation will try to retrieve a record with a known key, update it and read again to check if it was updated in the database. 例如,对更新操作的测试将尝试检索具有已知密钥的记录,更新它并再次读取以检查它是否在数据库中更新。

Although SQL scripts are not as easy to write and read as Rails fixtures, they're very fast and can do any kind of manipulation needed (eg DELETE, INSERT, UPDATE, execute stored procedures). 虽然SQL脚本不像Rails夹具那样易于编写和读取,但它们非常快并且可以进行任何需要的操作(例如DELETE,INSERT,UPDATE,执行存储过程)。

This technique was well proven in a project involving 50 database tables and very complex business rules and processes. 这项技术在涉及50个数据库表和非常复杂的业务规则和流程的项目中得到了充分证明。 It kept the tests simple and consistent. 它使测试简单而一致。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM