测试期间如何处理DatabaseFacade(单元或集成)

时间:2020-09-23 21:04:00

标签: c# asp.net-core entity-framework-core

正在寻找一些建议。

public class SomeController : Controller
{
    private readonly SomeContextClass _context;
     
    public SomeController(SomeContextClass context)
    {
        _context = context;
    }   
}

//Context Class
public SomeContextClass : DbContext
{
    public SomeContextClass(DbContextOptions<SomeContextClass> op) : base(op){

        Database.SetCommandTimeout(9000);
    }
}

//Test
[Fact]
public void SomeController_Test()
{
    //Trying In-Memory Implementation
    var options = new DbContextOptions<SomeContextClass>().UseInMemoryDatabase(databaseName: "SomeDB").Options;

    using (var context = new SomeContextClass(options))
    {
        var sc = new SomeController(context);
    }
}

由于setcommandtimeoutcall,尝试初始化某些上下文类时出现此错误。

有没有一种使用最小起订量来模拟该呼叫的方法? 如何在内存测试中处理它?<​​/ p>

3 个答案:

答案 0 :(得分:0)

我今晚看了一眼,因为我期望它会引发InvalidOperationException

仅当上下文使用关系数据库提供程序时,才可以使用特定于关系的方法。

当您尝试使用诸如FromSql,ExecuteSqlCommand等关系方法时,这些在内存提供程序中很常见。大多数情况下,可以使用模拟包装器对它们进行模拟(我对我的库EntityFrameworkCore.Testing做到了这一点),但通常需要做很多工作。

SetCommandTimeout是扩展。您需要深入研究扩展,并在数据库外观上模拟一些内容才能使其正常工作。

但是,在我们走这条路之前,在这种情况下,模拟对您不起作用。在模拟实现时,模拟库需要能够创建实例以进行代理,这意味着它将在构造函数中执行代码。 SetCommandTimeout将在模拟创建过程中生成的任何传递给您的DbContextOptions上执行,并再次执行barf。

根据您的选择:

  1. 不要在构造函数中调用set命令超时;将其移至另一种方法,记得调用它,等等

  2. 使用支持关系操作的其他实体框架核心提供程序

不能说我喜欢第一个选项,但是它将允许您模拟它。第二个更可口。我对SQLite并没有做很多事情,但是快速使用LINQPad可以产生预期的结果:

void Main()
{
    using (var connection = new SqliteConnection("Filename=:memory:"))
    {
        connection.Open();
        var options = new DbContextOptionsBuilder<TestDbContext>().UseSqlite(connection).Options;
        var testDbContext = new TestDbContext(options);
        Console.WriteLine(testDbContext.Database.GetCommandTimeout());
    }
}

public class TestDbContext : DbContext
{
    public TestDbContext(DbContextOptions<TestDbContext> op) : base(op)
    {
        Database.SetCommandTimeout(9000);
    }
}

结果:

enter image description here

答案 1 :(得分:0)

您可以set it through DbContextOptions,而不是在DbContext配置中对超时进行硬编码。这样,上下文类保持不变。

从链接文档的示例中,您可以使用设置提供商特定的命令超时:

optionsBuilder
    .UseSqlServer(connectionString, 
        providerOptions=>providerOptions.CommandTimeout(90));

这可用于生产或集成测试中,以设置真实数据库的命令超时,而无需修改DbContext:

var options = new DbContextOptions<SomeContextClass>()
        .UseSqlServer(connectionString, 
            providerOptions=>providerOptions.CommandTimeout(90))
        .Options;

超时值可以来自配置,可以在不修改代码的情况下对其进行更改。

使用内存提供程序的单元测试虽然不需要该设置,所以可以将其省略。

var options = new DbContextOptions<SomeContextClass>()
                 .UseInMemoryDatabase(databaseName: "SomeDB")
                 .Options;

答案 2 :(得分:0)

不是真正的解决方案,但我想在这里留下一个解决方法的指针,因为 this answer 挽救了我的一天。我只需要 DatabaseFacade 中的一件事就可以让我的代码进行单元测试,最后我用我可以模拟的数据库上下文的虚拟方法包装它:

   public virtual bool CanConnectToDatabase()
   {
       return Database.CanConnect();
   }
相关问题