【问题标题】:Unit Testing a function dealing with database records单元测试处理数据库记录的函数
【发布时间】:2018-06-27 17:35:51
【问题描述】:

单元测试应该只测试一个函数的逻辑,并且应该“模拟”该函数中使用的数据。我想知道我们如何将以下功能与“模拟”数据结合起来?或者即使它是正确的方法。函数签名是

    public String doSomething(int firstId, int secondId, int count){
     //this function looks in a table e.g. C which has foreign keys from table A, and B
    //if firstId and secondId exist in db table C return "already-exists"
    //if count < a_column_value_in_table_C return "not-allow"
    // else return "success"
    }

firstIdsecondId 是两个不同表的外键。现在,我们如何对这个函数进行单元测试: 1. 应该如何设计单元测试,以便能够在函数中测试 3 个 scnarios 2. 我们如何为这个单元测试准备数据,因为它需要来自两个不同表的外键。

【问题讨论】:

  • "//this function looks in a table e.g. C..." - 这个函数是如何做到的?我会假设通过一些 JDBC 层,例如CRUD 存储库?如果是这样:模拟并注入这一层 --- “... 所以它能够测试 3 个 scnarios ...” - 三个场景,三个不同的测试,三个不同的模拟。
  • 嗨@Turing85 目前测试类正在使用“真实”存储库,使用模拟存储库是有意义的,我仍然不完全理解这是如何工作的,但我会研究它但是您的方法使用模拟 crud depos 是有意义的

标签: java unit-testing tdd


【解决方案1】:

您应该使用 Solid 原则中的依赖注入。 doSomething 方法的所有者应该注入一些 Repository 或 DAO 等。

在您的单元测试中,您应该模拟存储库方法。

例如,假设您的 doSomething 方法调用了存储库的 findById(...) 方法。您应该通过所需的输出模拟 findById 方法,并只测试流程的逻辑部分。

【讨论】:

    【解决方案2】:

    您可以使用一些测试数据库或内存中的数据库(如 HSQLDB)。在测试之前用一些测试数据填充它(在注解 @BeforeClass 的方法中,或者如果您使用 Spring,则在测试数据源初始化期间)。然后对传递准备好的数据的所有场景执行测试。用@AfterClass注解的方法清理测试数据库中的数据。

    如果您使用 Spring 并在 XML 配置中配置测试数据源可能如下所示:

    <jdbc:embedded-database id="dataSource" type="HSQL" >
      <jdbc:script location="scripts/ddl/*"/> <!-- create tables -->
      <jdbc:script location="scripts/dml/*"/> <!-- populate test data -->
    </jdbc:embedded-database>
    

    【讨论】:

      【解决方案3】:

      我通常使用 getById 和 getAll 函数创建一个存储库接口。出于测试目的,我创建了一个内存存储库,而对于生产,我使用了数据库存储库。

      这里是一个例子:

      public interface Repository<T> {
        public T getById(int Id);
        public List<T> getAll();
      }
      
      public InmemoryRepository implements Repository<User> {
       List<User> database = new ArrayList<>(); //with some data
       public List<User> getAll() { 
        return database;
       }
       public User get(int Id) {
         return database.stream().filter(x -> x.Id = Id).collect(Collectors.asList());
       }
      }
      

      在您的函数中注入此存储库,以便您可以通过以下方式访问数据库:

      public String doSomething(int firstId, int secondId, int count, Repository<User> repo){};
      

      【讨论】:

      • 如果此答案对您有帮助,请将其标记为已接受。如果没有,请为我进一步澄清。
      【解决方案4】:
      1. 你不应该设计一个单元测试来匹配所有的情况。为每种情况创建不同的单元测试。

      2. 您需要模拟访问数据库的存储库或类,使其不会在数据库中执行,而是返回您在单元测试中预先确定的结果集。有一些模拟库,这使您的工作变得非常容易。如果代码只是执行查询或过程并返回结果,那么为它编写单元测试并没有多大价值,在这种情况下编写集成测试就足够了。

      P.S:Emre Savcı,依赖注入不是一个可靠的原则,依赖倒置是。它们根本没有关系。

      【讨论】:

        猜你喜欢
        • 2013-04-13
        • 1970-01-01
        • 2018-07-22
        • 2012-04-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多