我正在尝试为我的ASP.NET Web API项目编写单元/集成测试,并努力孤立地运行每个测试。请允许我解释一下。
我有一个配置了部署设置的* .testsettings文件。在每次测试运行之前,将一个空的* .mdf文件部署到测试位置。由于我正在使用实体框架代码优先,我可以使用数据库初始化程序将我的模式推送到数据库并为2行播种特定的表。这很有效。
我面临的问题是,如果他们以错误的顺序执行,我所有ApiControllers操作的各种测试都会踩到彼此的脚趾上。例如,如果我在POST测试之前运行GET测试,那么GET将返回2个对象,如果它们以相反的顺序运行,那么GET将返回3个对象。
我认为我需要做的是在每次测试之前删除,重新创建和重新设置我的数据库。这是个好主意还是有更好的方法?如果这是我能做的最好的,我会在每次测试之前重新设置数据库。
答案 0 :(得分:21)
这是我最终为感兴趣的人做的事情。
我扩展了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());
}
}
这为数据库设置了初始值设定项,但实际上并没有运行它。 intitializer在我编写的[TestInitialize]
方法中运行,该方法强制在每次测试之前删除,重新创建和重新植入数据库。
[TestClass]
public class MyTestClass
{
[TestInitialize]
public void TestInitialize()
{
MyDbContext context = new MyDbContext();
context.Database.Initialize(true);
}
[TestMethod]
public void MyUnitTest()
{
Assert.IsTrue(true);
}
}
答案 1 :(得分:6)
我建议在开始测试之前重新创建数据库,然后将每个数据库包装在一个总是回滚的事务中。如果您的重新创建阶段需要花费大量时间来完成(例如,由于需要执行的操作等),这非常有用。
答案 2 :(得分:1)
在我们当前的设置中,我们在每个类加载之前重新创建数据库模式(使用ClassInitialize属性,但这肯定可以移动到AssemblyInitialize),并且只需在每个类之前/之后使用适当的记录来播种/清理数据库测试运行(使用TestInitialize / TestCleanup属性)。
更多信息:http://msdn.microsoft.com/en-us/library/ms379625(v=vs.80).aspx