在 Effort 数据库上创建存储过程以进行单元测试

GGO*_*GGO 3 c# unit-testing stored-procedures entity-framework effort

我有一个使用实体框架调用存储过程的函数:

public async Task<List<Entity>> GetEntity(int id)
{
       var param = new SqlParameter("@id", id);
       return await myContext.Database
           .SqlQuery<MyEntity>("[myStoredProcedure] @id", param)
           .ToListAsync();
}
Run Code Online (Sandbox Code Playgroud)

我想使用 Effort 为其创建一个单元测试。我已经有努力(和 NMemory 数据库)来模拟数据库(基于我的上下文),Initialize针对每个单元测试,例如:

[TestInitialize]
public void Initialize()
{
     Effort.Provider.EffortProviderConfiguration.RegisterProvider();
     EffortProviderFactory.ResetDb()
     using (var context = new MyContext("PWET"))
     {
          context.Database.CreateIfNotExists();
          context.Constructeurs.Add(new Constructeur { Nom = "Zebra" });
          context.Constructeurs.Add(new Constructeur { Nom = "Joya" });
          context.SaveChanges();
     }
}
Run Code Online (Sandbox Code Playgroud)

哪里EffortProviderFactory

public class EffortProviderFactory : IDbConnectionFactory
{
    private static DbConnection _connection;
    private readonly static object _lock = new object();

    public static void ResetDb(){
        lock (_lock){
            _connection = null;
        }
    }
    public DbConnection CreateConnection(string nameOrConnectionString)
    {
        lock (_lock){
            if (_connection == null)
                _connection = Effort.DbConnectionFactory.CreateTransient();
            return _connection;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我测试了添加存储过程创建,如下所示:

[TestInitialize]
public void Initialize()
{
     Effort.Provider.EffortProviderConfiguration.RegisterProvider();
     EffortProviderFactory.ResetDb()
     using (var context = new MyContext("PWET"))
     {
          context.Database.CreateIfNotExists();
          context.Database.ExecuteSqlCommand(@"
CREATE PROCEDURE [dbo].[myStoredProcedure]
@id INT = 0
AS
BEGIN

SELECT foo
FROM bar 
WHERE foo.Id = @id

ORDER BY foo.Id;
END");
     }
}
Run Code Online (Sandbox Code Playgroud)

但它会抛出一个NotSupportedException. 我该怎么办,最好的方法是什么?

Ger*_*old 6

Effort是一个基于文件的内存数据库提供程序,为DbContext实例提供私有临时数据库:新上下文、新数据库、无测试交互。这是好的部分。

当然,缺点是它不是——也永远不会是——一个成熟的数据库引擎。因此,它永远不会支持用任何常见 SQL 方言(如 t-SQL 或 PL-SQL)编写的存储过程。就Effort(即NMemory)有存储过程而言,它只是一个存储过程,从构造函数IQueryable可以明显看出。注意与 t-SQL 存储过程远程相关。StoredProcedure

在数据访问层代码中测试存储过程的唯一方法(这是一个非常好的主意)是编写集成测试。使集成测试彼此独立的方法大致有两种:

  • 为每个测试创建/播种一个新数据库

  • 将现有数据库与测试用例一起使用,并在每次测试后回滚更改,例如使用 TransactionScope

集成测试永远不会像单元测试那么快,它们只是补充单元测试,但尽管如此,在我自己与数据层相关的编码实践中,它们已经成为测试套件中的一等公民。对我来说,正确性比速度更重要。

  • @GGO 支持 Gert 的答案,[Effort FAQ](https://effort.codeplex.com/wikipage?title=FAQ) 部分包含以下内容:*“**它有任何限制吗?** 是的,它可以仅模拟通过实体框架管道的操作。这意味着数据库特定操作无法工作(例如:ExecuteStoreCommand)。存储过程、视图和触发器也无法模拟。”* (2认同)