【问题标题】: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);
     }

   }

}

【问题讨论】:

    标签: c# unit-testing testing persistence data-access-layer


    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-04
      • 1970-01-01
      • 2015-07-13
      • 2011-01-23
      • 2015-11-27
      • 2011-02-16
      • 2011-10-24
      • 1970-01-01
      相关资源
      最近更新 更多