单元测试处理数据库记录的函数



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

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. 我们如何为这个单元测试准备数据,因为它需要来自两个不同表的外键。

你应该使用来自 Solid 原则的依赖注入。 doSomething方法所有者的类应该注入一些存储库或DAO等。

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

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

您可以使用一些测试数据库或内存数据库(如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>

我通常创建一个带有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){};
  1. 您不应该设计一个单元测试来匹配所有情况。对于每种情况,请创建不同的单元测试。

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

PS:Emre Savcı,依赖注入不是一个坚实的原则,依赖反转才是。它们根本没有关系。

最新更新