14

我正在尝试为我的 ASP.NET Web API 项目编写单元/集成测试,并努力单独运行每个测试。请允许我解释一下。

我有一个配置了部署设置的 *.testsettings 文件。在每次测试运行之前,都会将一个空的 *.mdf 文件部署到测试位置。由于我使用的是 Entity Framework Code First,因此我可以使用数据库初始化程序将我的模式推送到数据库并为具有 2 行的特定表提供种子。这很好用。

我面临的问题是,如果我的所有 ApiControllers 动作的各种测试以错误的顺序执行,它们可能会踩到对方的脚趾。例如,如果我在 POST 测试之前运行 GET 测试,则 GET 返回 2 个对象,如果它们以相反的顺序运行,则 GET 返回 3 个对象。

我认为我需要做的是在每次测试之前删除、重新创建和重新植入我的数据库。这是一个好主意还是有更好的方法?如果这是我能做的最好的,我会在每次测试之前重置我的数据库。

4

3 回答 3

23

这就是我最终为任何感兴趣的人所做的事情。

我扩展DropCreateDatabaseAlways<TContext>并覆盖了 Seed 方法,用我的单元测试可以依赖的已知测试数据填充我的数据库。

public class MyDatabaseInitializer : System.Data.Entity.DropCreateDatabaseAlways<MyDbContext>
{
    protected override void Seed(MyDbContext context)
    {
        // Add entities to database.

        context.SaveChanges();
    }
}

然后我实现了一个[AssemblyInitialize]设置数据库初始化程序的方法。

[TestClass]
public class Global
{
    [AssemblyInitialize]
    public static void AssemblyInitialize(TestContext context)
    {
        System.Data.Entity.Database.SetInitializer(new MyDatabaseInitializer());
    }
}

这会设置数据库的初始化程序,但不会实际运行它。初始化程序以[TestInitialize]我编写的方法运行,该方法强制在每次测试之前删除、重新创建和重新植入数据库。

[TestClass]
public class MyTestClass
{
    [TestInitialize]
    public void TestInitialize()
    {
        MyDbContext context = new MyDbContext();
        context.Database.Initialize(true);
    }

    [TestMethod]
    public void MyUnitTest()
    {
        Assert.IsTrue(true);
    }
}
于 2012-12-21T14:36:23.860 回答
6

我建议在开始测试之前重新创建数据库,然后将每个数据库包装在始终回滚的事务中。如果您的重新创建阶段需要大量时间才能完成(例如,因为需要执行的操作等),这将非常有益。

于 2012-12-06T08:12:39.983 回答
1

在我们当前的设置中,我们在加载每个类之前重新创建数据库模式(使用 ClassInitialize 属性,但这肯定可以移动到 AssemblyInitialize),并且只是在每次测试运行之前/之后使用适当的记录播种/清理数据库(带有 TestInitialize/TestCleanup 属性)。

更多信息: http: //msdn.microsoft.com/en-us/library/ms379625 (v=vs.80).aspx

于 2012-12-05T22:45:19.893 回答