如何在Visual Studio 2012和Entity Framework 5中设置LocalDb用于单元测试

62
我们有一个使用Entity Framework 5的Visual Studio 2012 ASP.NET MVC项目,其中有一些依赖于数据库的单元测试。在测试项目中设置app.config文件以使用中央SQL Server数据库是可以的。然而,最好使用LocalDb来使每个开发人员在运行测试时拥有自己的数据库,尤其是由于我们希望在运行时将测试设置为DropCreateDatabaseAlways。但是,我无法让设置工作。如果我在app.config中尝试这样做:
<add name="TestDb" 
   connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=unittestdb;
     Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\unittestdb.mdf"
   providerName="System.Data.SqlClient" />

我收到的错误信息是:

System.Data.SqlClient.SqlException:发生文件激活错误。 物理文件名 '\unittestdb.mdf' 可能不正确。诊断并纠正其他错误,然后重试操作。创建数据库失败。列出了一些无法创建的文件名。请检查相关错误。

听起来它希望 mdf 文件已经存在,这似乎很奇怪,因为它正在尝试创建数据库。手动创建 mdf 文件不会改变错误消息。


1
你能检查一下在单元测试中调用 AppDomain.CurrentDomain.GetData("DataDirectory") 时你得到了什么值吗? - Ladislav Mrnka
在单元测试中,AppDomain.CurrentDomain.GetData("DataDirectory") 的值为 null - Klas Mellbourn
1
要么使用 SetData 将值设置为某个路径,要么不在连接字符串中使用 |DataDirectory|,因为它是 null - Ladislav Mrnka
删除|DataDirectory|\部分并没有帮助,我仍然得到相同的错误。但是,用C:\Temp\替换它确实有所帮助!然后单元测试再次运行。这是一个很大的改进。锦上添花的是,如果数据库可以驻留在相对路径中,那就更好了。 - Klas Mellbourn
2
既然你已经找到了解决方案,能否回答自己的问题并接受答案呢? - sharakan
显示剩余2条评论
5个回答

34

尝试:

AppDomain.CurrentDomain.SetData(
  "DataDirectory", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ""));

这将在 /bin/Debug/ 目录下创建名为 yourdbname.mdf 的数据库文件。


10

我会使用:

// Declare this property - this is set by MSTest
public TestContext TestContext { get; set; }

// In test initialization - note the signature should be exactly this
// A static void method with one argument of type TestContext 
[ClassInitialize]
public static void SetUp(TestContext context)
{
   AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(context.TestDeploymentDir, string.Empty));
}

使用 AppDomain.CurrentDomain.BaseDirectory 可能会出现问题,建议改用: context.TestDeploymentDir


1
context 是什么类型的变量,它来自哪里? - Jesse Webb
3
将这样的一个属性添加到你的测试类中,MSTest会自动注入它:public TestContext TestContext { get; set; } - Jupaol
你能解释一下为什么在设置方法中执行这个操作比仅在我的 new Migrations.Configuration(); 之前执行更好吗? - bbodenmiller

3
请记住,在测试项目中:
AttachDBFilename=|DataDirectory|
意味着它将在你的输出/bin/debug文件夹中查找单元测试,而不是Web/生产/任何应用程序中的App_Data文件夹。
你需要做两件事:
1. 将数据库文件移出App_Data文件夹,移到你测试应用程序的根目录下。
2. 高亮显示你的数据库,这样你就能在Visual Studio中获得属性窗口。将构建操作设置为“内容”,这样当你运行项目时,它将被复制到输出文件夹中。
完成了。

1
我建议使用这段代码(基于Jupaol的回答):
[ClassInitialize]
public static void SetUp(TestContext context)
{
    AppDomain.CurrentDomain.SetData(
        "DataDirectory", 
        context.TestDeploymentDir);
}

通常情况下,这将在您的解决方案的TestResults\<test run>\Out\文件夹内创建您的数据库。

嗨,使用VS 2013时,在“Debug Tests”模式下运行我的单元测试可以正常工作。但是在运行“Run All”测试时失败了。我该如何使它在“Run All”模式下正常工作? - Martin

0
我在寻找问题的答案时发现了你的问题。在一个单独的项目中使用EntityFramework和nUnit,我不得不更改App.config文件。
它看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>


那个在使用 DataSource 属性的 UnitTest 中有效吗? - JWP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接