Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 集成测试EF5(或EF4x)_C#_Asp.net Mvc 3_Entity Framework_Unit Testing_Integration Testing - Fatal编程技术网

C# 集成测试EF5(或EF4x)

C# 集成测试EF5(或EF4x),c#,asp.net-mvc-3,entity-framework,unit-testing,integration-testing,C#,Asp.net Mvc 3,Entity Framework,Unit Testing,Integration Testing,在阅读了关于单元测试实体框架的几个问题/答案之后,我决定放弃单元测试以进行集成测试。我的理念是,与EF环境交互是一种“私人”行为,因为它不需要独立于我的服务进行单元测试,也不容易准确地被嘲笑 注意:在我的示例中,我使用的是EF5 首先,我有一个创建用户的服务方法: void CreateUser(string username, string password); 我的测试程序集有一个SetUpFixture(一次性用于测试运行),用于创建我的数据库(EF代码优先)和测试数据: [SetUpF

在阅读了关于单元测试实体框架的几个问题/答案之后,我决定放弃单元测试以进行集成测试。我的理念是,与EF环境交互是一种“私人”行为,因为它不需要独立于我的服务进行单元测试,也不容易准确地被嘲笑

注意:在我的示例中,我使用的是EF5

首先,我有一个创建用户的服务方法:

void CreateUser(string username, string password);
我的测试程序集有一个SetUpFixture(一次性用于测试运行),用于创建我的数据库(EF代码优先)和测试数据:

[SetUpFixture]
public class SetUpFixture
{
    [SetUp]
    public void SetUp()
    {
        using (var context = new MyDbContext())
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<MyDbContext>());

            // Set up a bunch of initial data and commit
        }
    }
}
最后,我进行了实际的集成测试,以确保传入了哪些有效数据,并创建了一个带有我用户名的记录(这就是我的问题所在):

以下是我的问题:

1) 首先,这甚至是测试依赖于EF的服务的方式吗?我知道有几种方法,我只是想确保这种方法没有什么疯狂之处

2) 其次,在提交数据之前,我应该如何验证服务方法(CreateUser)是否执行了它应该执行的操作(我不希望它提交数据,以便我的数据库状态保持在每次测试之前初始化的状态)?上述测试中的查询未返回任何数据,因为它尚未提交。

对于#2,如果您使用的是SQL Server,则可以使用。在加载测试数据时创建快照。然后,运行测试,在拆卸(或使用的任何测试后方法)中,恢复到快照。恢复到快照非常快,因此这是测试DB的一种实用方法

还有另一种方法,我已经用它取得了一些成功。不要使用SQL数据库,而是使用SQLCE数据库。然后,您可以将测试数据作为文件进行管理—您仍然在创建数据库。我更喜欢快照方法,但它们都有效

对于#1,这是一个集成测试。在测试应用程序的数据部分时,访问数据库正是正确的做法。抽象出存储库只会给您带来更大的复杂性,因为您需要根据数据库测试存储库

祝你好运,
Erick

这接近于我所有的自动化测试(我也不进行单元测试,只针对真实数据库进行集成测试)。有两件事我做得不同

首先,我在我的设置中设置了transactionscope,并在我的拆卸中处理它,而不提交。这允许我查询更新的数据w 但是能够为下一次测试还原数据库。缺点是您可能无法在服务层中使用TransactionScope,因为我不知道嵌套事务的工作情况如何


我要做的另一件事是在启动时通过调用EF initialize类触发完整的数据库重建(我前面没有代码)。通过这种方式,我可以保证在测试运行开始时从种子数据中获得一个新的数据库,并且它还可以让我知道我的实体结构是否糟糕,

在集成界面上验证预期的行为。假设您对EF的行为有信心,您可以始终在存储库对象中模拟EF,从而减少回滚数据更改的必要性。如果做不到这一点,只需在每次测试之前再次进行数据设置。我没有使用存储库——我的服务直接绑定到EF。我知道很多人反对这种设计,但我已经准备好了@LadislavMrnka的许多帖子,这些帖子给出了非常有效的理由,说明为什么应该避免使用EF进行存储库和真正的单元测试。谁?您当然不必使用存储库(更改底层数据存储不是常见的情况),但我想不出任何不使用存储库的邪恶理由,存储库确实为您提供了一些很好的组织能力。请参阅他的理由和讨论此问题的几个链接。好的,然后在每次测试之前再次设置测试数据。应该很简单。有趣的是,大约10分钟前我遇到了同样的情况。事实上,我已经让我的设置完成了数据库的删除/重新创建,并设置了我的设备。所以我所需要做的就是用TransactionScope包装我的测试。我做到了,现在我准备好了。关于服务,我不打算在测试之外使用MSDTC。事实上,我发现在谈论IoC和嵌套UoW时,可能会尝试这样做。正如我在下面的评论中提到的,如果您的测试包含错误,您可以在测试中使用事务时轻松掩盖失败。在下面的评论中,您没有详细说明事务将隐藏哪些错误。谢谢,Erick。你的回答让我找到了,这和你做的一样。然而,这位博主后来发表了文章,这就是我最后所做的(见下面KallDrexx的回答)。我最终接受了他的答案,但你还是得到了一个+1,因为你最初把我带到了这里。再次感谢!这是一个很好的方法,但我想警告您,如果您的测试包含任何错误条件,那么您可能最终会得到不应该通过的测试,反之亦然。如果我的测试包含错误条件,你是什么意思?为什么这种方法会有误报的风险?sql server快照是否足够快,可以在每次测试之间恢复?谢谢你的链接,我以前从来都不知道这些。足够快是一个很难回答的问题。:)我发现它们足够快,可以在几分钟内运行大约100个测试。另一件好事是,即使完全更改了数据,恢复速度也同样快。可以将其视为指针更改。
[TestFixtureSetUp]
public virtual void TestFixtureSetUp()
{
    _context = new MyContext(rollbackOnDispose: true);
    UserService = new SignupService(_context);
}

[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
{
    Context.Dispose();
}
[Test]
public void ValidDataShouldResultInNewRecordWithUsername()
{
    SignupService.CreateUser("myuser", "fakepassword");

    var q = from user in Context.Users 
            where user.Username == "myuser"
            select user;

    var actualUser = q.Single();

    Assert.AreEqual("myuser", actualUser.Username);
}