单元测试应仅测试一个功能的逻辑,并应“模拟”该功能中使用的数据。我想知道如何将以下功能与“模拟”数据结合在一起?甚至是正确的方法函数签名是
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"
}
firstId
和secondId
是形成两个不同表的外键。现在,我们如何根据以下方面对这个功能进行单元测试:
1.应该如何设计单元测试,以便能够在功能中测试3个场景
2.考虑到需要来自两个不同表的外键,我们如何为该单元测试准备数据。
答案 0 :(得分:3)
您应该使用Solid Principle中的依赖项注入。 拥有doSomething方法所有者的类应注入一些存储库或DAO等。
在单元测试中,您应该模拟存储库方法。
例如,假设您的doSomething方法调用存储库的findById(...)方法。您应该通过所需的输出来模拟findById方法,并仅测试流程的逻辑部分。
答案 1 :(得分:2)
我通常使用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){};
答案 2 :(得分:2)
您可以使用某些测试数据库或内存数据库(例如HSQLDB)。在测试之前(在带有注释的方法@BeforeClass
中或在测试数据源初始化期间,如果使用Spring,则在其中填充一些测试数据)。然后对传递预备数据的所有方案执行测试。用@AfterClass
注释的方法清除测试数据库中的数据。
如果您使用Spring并在XML config中配置测试数据源,则可能如下所示:
<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 :(得分:1)
您不应该设计一个单元测试来匹配所有情况。对于每种情况,请创建一个不同的单元测试。
您需要模拟访问数据库的存储库或类,以便它不会在数据库中执行,而是返回您在单元测试中预定的结果集。有为此的模拟库,这使您的工作非常轻松。如果代码仅执行查询或过程并返回结果,则为它编写单元测试没有太多优点,在这种情况下,编写集成测试应该就足够了。
P.S:EmreSavcı,依赖注入不是一个坚实的原则,依赖反转是。它们根本不相关。