我一直在寻找一种有效的方法来在C#中对我的数据访问层进行单元测试。我是主要的Java开发人员,并且只使用了C#大约6个月,过去我使用了一个名为DBUnit的库来测试已知的状态数据库。我找不到一个可以使用的类似活动库,最近似乎是nDBUnit,但它现在还没有激活。
C#中的方法和原因似乎有很多相互矛盾的方法。理想情况下,我想使用模拟测试数据访问层,而无需连接到数据库,然后在一组单独的测试中对存储过程进行单元测试。
在我正在研究的系统中,数据访问层将使用ADO.net(不使用实体框架)在SQL Server上调用存储过程。
以下是我必须使用的示例代码;沿着模拟路径,我必须能够模拟SqlCommand(使用IDbCommand)和/或模拟SqlConnection。
所以我的问题是什么似乎是最好的方式(如果有这样的事情)这样做?到目前为止,唯一的方法是将代理对象传递给构造函数,以便它可以返回模拟的Sql *对象进行测试。
我还没有机会查看所有可用的C#模拟库。
public class CustomerRepository : ICustomerRepository
{
private string connectionString;
public CustomerRepository (string connectionString)
{
this.connectionString = connectionString;
}
public int Create(Customer customer)
{
SqlParameter paramOutId = new SqlParameter("@out_id", SqlDbType.Int);
paramOutId.Direction = ParameterDirection.Output;
List<SqlParameter> sqlParams = new List<SqlParameter>()
{
paramOutId,
new SqlParameter("@name", customer.Name)
}
SqlConnection connection = GetConnection();
try
{
SqlCommand command = new SqlCommand("store_proc_name", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddRange(sqlParams.ToArray());
int results = command.ExecuteNonQuery();
return (int) paramOutId.Value;
}
finally
{
CloseConnection(connection);
}
}
}
答案 0 :(得分:21)
遗憾的是,您无法找到将数据库置于已知状态的工具,并允许您针对数据库运行CustomerRepository以测试CustomerRepository。但是,答案不是开始使用模拟来模拟所有ADO调用。通过这样做,你最终创建了一个单元测试,它并没有真正测试任何逻辑:它只是测试代码是按照你认为应该编写的方式编写的。
假设我最终编写了一个SQL INSERT作为我在SQL数据库中创建客户的命令。现在让我们说我们正在进行更改,以便customer表具有不同的字段(这会破坏我们的INSERT命令),现在我们应该使用存储过程来创建客户。使用模拟的测试仍然会通过,即使它正在测试的实现现在已被破坏。此外,如果您将实现修复为使用存储过程,则单元测试现在将失败。如果单元测试在失败时继续通过但在修复系统时会失败,那么单元测试的重点是什么?
有关可能的替代方案,请参阅this question。看起来标记的答案实际上是最终使用IKVM在C#中使用DBUnit。
所以,可能还有其他方法可以继续探索,但嘲笑ADO调用只会导致脆弱的测试,而这些测试并没有真正测试任何重要的东西。
答案 1 :(得分:2)
该层的工作是将代码连接到数据库。它必须封装有关db连接和语法的知识。通常将域语言映射到数据库语言。我将单元测试的这一部分看作集成测试,因此我测试数据库模式与真实或测试数据库等效。有关该主题的更多信息here。
答案 2 :(得分:1)
要测试DataAccess Layer,您需要一个更复杂的结构。
DataAccess Layer将调用Repository对象的引用。 Repo对象将通过UnitOfWork设计模式调用Entity Framework DbSets中的引用。
DataAccess Layer(TOP)
|
的UnitOfWork
|
存储库模式类
|
EF背景
|
实际数据库
设置结构后,您将模拟存储库类。例如,项目将被插入到DB而不是模拟对象。稍后您将断言您的模拟对象以查看是否插入了项目。