单元测试数据访问层的方法
Posted
技术标签:
【中文标题】单元测试数据访问层的方法【英文标题】:Ways of unit testing data access layer 【发布时间】:2013-02-06 16:43:59 【问题描述】:我一直在尝试寻找一种有效的方法来用 C# 对我的数据访问层进行单元测试。我是一名 Java 开发人员,只使用了大约 6 个月的 C#,过去我使用一个名为 DBUnit 的库来针对已知状态数据库进行测试。我还没有找到可以使用的类似活动库,最接近的似乎是 nDBUnit,但它已经有一段时间没有活动了。
似乎在 C# 中如何以及为什么有很多相互矛盾的方法。理想情况下,我想使用模拟测试数据访问层,而无需连接到数据库,然后在单独的一组测试中对存储过程进行单元测试。
在我正在开发的系统中,数据访问层是使用 ADO.net(不使用实体框架)来调用 SQL Server 上的存储过程。
以下是我必须使用的示例代码;要沿着模拟路径走下去,我必须能够模拟 SqlCommand(使用 IDbCommand)和/或模拟 SqlConnection。
所以我的问题是什么似乎是最好的方法(如果有这样的事情)来做到这一点?到目前为止,唯一的方法是制作传递给构造函数的 Proxy 对象,以便它可以返回模拟的 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);
【问题讨论】:
【参考方案1】:很遗憾,您找不到将数据库置于已知状态并允许您针对数据库运行 CustomerRepository 以测试 CustomerRepository 的工具。但是,答案不是开始使用模拟来模拟所有的 ADO 调用。通过这样做,您最终会创建一个不真正测试任何逻辑的单元测试:它只是测试代码是否按照您认为应该编写的方式编写。
假设我最终编写了一个 SQL INSERT 作为在 SQL 数据库中创建客户的命令。现在假设我们正在进行更改,以便客户表具有不同的字段(这会破坏我们的 INSERT 命令),现在我们应该使用存储过程来创建客户。使用模拟的测试仍然可以通过,即使它正在测试的实现现在已经被破坏了。此外,如果您将实现修复为使用存储过程,您的单元测试现在将失败。如果单元测试在应该失败时继续通过,但在您修复系统时会失败,那么单元测试的意义何在?
请参阅this question 了解一些可能的替代方案。看起来标记的答案实际上只是最终使用 IKVM 在 C# 中使用 DBUnit。
因此,可能还有其他途径可以继续探索,但模拟 ADO 调用只会导致脆弱的测试,而这些测试并不能真正测试任何重要的东西。
【讨论】:
谢谢,我在周末给了这个更好的外观,我同意测试应该访问一个真实的数据库,对于我们的 Java 项目,它的工作方式就像这样,特别是表和列名已经更改为项目增长了。我看了一下 IKM 方法,我不想介绍太复杂的东西,其他开发人员无法管理和理解。 没错,这就是您应该创建使用存储库/DAL 的服务的原因。您模拟存储库,将其注入服务并测试该服务。然后,您将单独测试服务中的逻辑。如果存储库中断(返回不正确的数据),逻辑将失败,测试将失败。看到人们嘲笑存储库然后断言从该存储库返回总是很有趣。你没有用它来测试任何东西。【参考方案2】:这一层的工作是将代码连接到数据库。它必须封装有关数据库连接和语法的知识。通常将领域语言映射到数据库语言。我将单元测试的这一部分视为集成测试,因此我测试数据库模式是否与真实数据库或测试数据库等效。有关该主题的更多信息here。
【讨论】:
谢谢,我觉得我看得太多了,我本来想这样做,但由于 c# 中缺乏这样的库,我开始寻找替代方案。【参考方案3】:要测试 DataAccess Layer,您需要一个更复杂的结构。
DataAccess Layer 将从 Repository 对象调用引用。 Repo 对象将通过 UnitOfWork 设计模式从 Entity Framework DbSets 调用引用。
数据访问层 (TOP) | 工作单位 | 存储库模式类 | 英孚上下文 | 实际数据库
设置结构后,您将模拟存储库类。例如,项目将被插入到数据库中,而不是进入模拟对象。稍后您将对模拟对象进行断言以查看是否插入了项目。
请看Implementing the Repository and Unit of Work Patterns
【讨论】:
以上是关于单元测试数据访问层的方法的主要内容,如果未能解决你的问题,请参考以下文章