2014-10-08 83 views
3

在我的应用程序有共享同一数据库的多个小实体框架dbcontexts多个实体框架dbcontexts,例如:集成测试共享数据库

public class Context1 : DbContext { 
    public Context1() 
     : base("DemoDb") { 
    } 
} 

public class Context2 : DbContext { 
    public Context2() 
     : base("DemoDb") { 
    } 
} 

所有数据库的更新将通过脚本完成,不依赖关于迁移(他们也不会前进)。问题是 - 你将如何对这些情况进行集成测试?

我认为有三个选项位置(可能还有更多我只是不知道他们)

选项1 - 超级语境 - 其中包含了设置数据库所需的所有型号和配置的上下文:

public class SuperContext : DbContext 
{ 
    public SuperContext() 
     : base("DemoDb") { 
    } 
} 

在这个选项中测试数据库将是对超环境和所有后续的测试设置将通过更小的环境来完成。 我不喜欢这个选项的原因是我将复制我已经构建的所有配置和实体模型。

选项2 - 创建集成测试自定义初始化器将运行所有相应的数据库初始化脚本:

public class IntegrationTestInitializer : IDatabaseInitializer<DbContext> { 

    public void InitializeDatabase(DbContext context) { 
     /* run scripts to set up database here */ 
    } 
} 

该选项允许对真正的数据库结构测试,但也需要更新每次新DB脚本添加

选项3 - 只是测试了个别的背景:

在这个选项中,可以让EF根据上下文创建测试数据库,并且所有测试都可以在自己的“沙箱”中运行。 我不喜欢这个的原因是,它不觉得你会测试数据库的真实表示。

我目前正在向选项2摇摆。你们都在想什么?那里有更好的方法吗?

回答

0

选项2或其任何运行实际数据库更新脚本的变体将是最好的。否则,您不一定需要针对生产中的相同数据库进行集成测试(至少就模式而言)。

为了解决您在每次添加新数据库脚本时都需要更新的问题,如果要将所有脚本保存在单个文件夹中,可能在构建操作为“复制更新”的项目中,您可以以编程方式读取每个文件并在其中执行脚本。只要你正在阅读文件的地方是更新脚本的标准库,你将永远不需要进入并做出任何进一步的修改。

+0

虽然我喜欢在每个文件中阅读的想法,这样我就不必更新初始化程序,唯一的问题是通常脚本需要按照某个顺序运行。例如,如果脚本1创建了一个表,但脚本2向该表添加了一个字段并且脚本2先运行,那么它将失败。我相信可以有一个解决方法,但 – tully2003 2014-10-09 11:49:14

+0

前缀带有ISO 8601格式的日期时间戳文件的名称。 – 2014-10-09 12:25:26

+0

是的,这将是一个明智的事情 - 不知道为什么我没有想到,但谢谢:) – tully2003 2014-10-09 13:04:05

4

我使用的集成测试很多,因为我仍然认为这是测试涉及数据相关进程时最可靠的方法。我也有几个不同的上下文,以及用于数据库升级的DDL脚本,所以我们的情况非常相似。

我最后的结果是选项4:通过常规用户界面维护单元测试数据库内容。当然,大多数集成测试临时修改数据库内容,作为测试“动作”阶段的一部分(更多信息请参见后面的“临时”),但测试会话启动时不会设置内容。

这是为什么。

在某个阶段,我们还通过代码或反序列化XML文件在测试会话开始时生成数据库内容。 (我们还没有EF,但是否则我们可能在数据库初始化器中有一些Seed方法)。渐渐地,我开始对这种方法感到担忧。当数据模型或业务逻辑发生变化时,维护代码/ XML是一团糟的工作,当需要设计新的用例时。有时候我会让自己对这些测试数据产生轻微的破坏,知道它不会影响测试。另外,数据必须有意义,因为它们必须与真实应用程序中的数据一样有效且一致。确保应用程序本身生成数据的一种方法,或者不可避免地会以某种方式在种子方法中复制业务逻辑。 嘲讽真实世界的数据其实很难很难这是我发现的最重要的事情。测试不代表实际使用情况的数据星座不仅是浪费时间,而且是错误的安全性。

因此,我发现自己通过应用程序的前端创建测试数据,然后将这些内容精心地序列化为XML或编写完全相同的代码。直到有一天,我发现我有这个数据库中的数据,所以为什么不直接使用它呢?

现在也许你问如何使测试独立?

集成测试,就像单元测试一样,应该可以独立执行。他们不应该依赖于其他测试,也不应该受其影响。我假设你的问题的背景是你为每个集成测试创建和种子数据库。这是实现独立测试的一种方法。

但是如果只有一个数据库,并且没有种子脚本呢?您可以为每个测试恢复备份。我们选择了不同的方法。每个集成测试都在永不承诺的TransactionScope内运行。这很容易实现。

[SetUp] 
public void InitTestEnvironment() 
{ 
    SetupTeardown.PerTestSetup(); 
} 

[TearDown] 
public void CleanTestEnvironment() 
{ 
    SetupTeardown.PerTestTearDown(); 
} 

和在SetupTeardown::每个测试夹具从基类,其具有这些方法(NUnit的)继承

public static void PerTestSetup() 
{ 
    _tranactionScope = new TransactionScope(); 
} 

public static void PerTestTearDown() 
{ 
    if (_tranactionScope != null) 
    { 
     _tranactionScope.Dispose(); // Rollback any changes made in a test. 
     _tranactionScope = null; 
    } 
} 

其中_tranactionScope是静态成员变量。

+1

感谢您花时间回答这个问题。您列出的测试的交易方面当然是有用的,我现在正在做的事情。 – tully2003 2014-10-10 14:14:34