在 Effort 数据库上为单元测试创建存储过程
Create stored procedure on Effort database for Unit Test
我有一个调用存储过程的函数 Entity Framework :
public async Task<List<Entity>> GetEntity(int id)
{
var param = new SqlParameter("@id", id);
return await myContext.Database
.SqlQuery<MyEntity>("[myStoredProcedure] @id", param)
.ToListAsync();
}
我想使用 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();
}
}
其中 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;
}
}
}
我测试了这样添加存储过程创建:
[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");
}
}
但它抛出 NotSupportedException
。我该怎么做,最好的方法是什么?
Effort 是一个基于文件的内存数据库提供程序,它为 DbContext
实例提供私有临时数据库:新上下文、新数据库、无测试交互。这是好的部分。
当然,缺点是它不是——而且永远不会是——一个成熟的数据库引擎。因此它将从不支持用任何常见SQL方言(如t-SQL或PL-SQL)编写的存储过程。至于Effort(即NMemory)有存储过程,它只是一个存储的IQueryable
,从StoredProcedure
constructor可以看出。注意到与 t-SQL 存储过程远程相关。
在数据访问层代码中测试存储过程的唯一方法是编写集成测试,这是一个很好的主意。大致有两种方法可以使集成测试相互独立:
Create/seed 每个测试一个新数据库
使用带有测试用例的现有数据库并在每次测试后回滚更改,for example using TransactionScope。
集成测试永远不会像单元测试一样快,它们只是 补充 单元测试,但是尽管如此,在我自己的与数据层相关的编码实践中,它们已经成为first-class 测试套件中的公民。对我来说,正确性比速度更重要。
我有一个调用存储过程的函数 Entity Framework :
public async Task<List<Entity>> GetEntity(int id)
{
var param = new SqlParameter("@id", id);
return await myContext.Database
.SqlQuery<MyEntity>("[myStoredProcedure] @id", param)
.ToListAsync();
}
我想使用 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();
}
}
其中 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;
}
}
}
我测试了这样添加存储过程创建:
[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");
}
}
但它抛出 NotSupportedException
。我该怎么做,最好的方法是什么?
Effort 是一个基于文件的内存数据库提供程序,它为 DbContext
实例提供私有临时数据库:新上下文、新数据库、无测试交互。这是好的部分。
当然,缺点是它不是——而且永远不会是——一个成熟的数据库引擎。因此它将从不支持用任何常见SQL方言(如t-SQL或PL-SQL)编写的存储过程。至于Effort(即NMemory)有存储过程,它只是一个存储的IQueryable
,从StoredProcedure
constructor可以看出。注意到与 t-SQL 存储过程远程相关。
在数据访问层代码中测试存储过程的唯一方法是编写集成测试,这是一个很好的主意。大致有两种方法可以使集成测试相互独立:
Create/seed 每个测试一个新数据库
使用带有测试用例的现有数据库并在每次测试后回滚更改,for example using TransactionScope。
集成测试永远不会像单元测试一样快,它们只是 补充 单元测试,但是尽管如此,在我自己的与数据层相关的编码实践中,它们已经成为first-class 测试套件中的公民。对我来说,正确性比速度更重要。