1. Overview
1.概述
Spring JdbcTemplate is a powerful tool for developers to focus on writing SQL queries and extracting results. It connects to the back-end database and executes SQL queries directly.
Spring JdbcTemplate是一个强大的工具,让开发者专注于编写SQL查询和提取结果。它连接到后端数据库并直接执行SQL查询。
Therefore, we can use integration tests to make sure that we can pull data from the database properly. Also, we can write unit tests to check the correctness of the related functionalities.
因此,我们可以使用集成测试来确保我们能够正确地从数据库中提取数据。同时,我们可以写单元测试来检查相关功能的正确性。
In this tutorial, we’ll show how to unit test JdbcTemplate code.
在本教程中,我们将展示如何对JdbcTemplate代码进行单元测试。
2. JdbcTemplate and Running Queries
2、JdbcTemplate和运行查询
Firstly, let’s start with a data access object (DAO) class that uses JdbcTemplate:
首先,让我们从一个使用JdbcTemplate的数据访问对象(DAO)类开始。
public class EmployeeDAO {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
public int getCountOfEmployees() {
return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM EMPLOYEE", Integer.class);
}
}
We dependency-inject a DataSource object into the EmployeeDAO class. Then, we create the JdbcTemplate object in the setter method. Also, we use JdbcTemplate in an example method getCountOfEmployees().
我们依赖注入一个DataSource对象到EmployeeDAO类。然后,我们在setter方法中创建JdbcTemplate对象。另外,我们在一个例子方法JdbcTemplate中使用getCountOfEmployees().。
There are two ways to unit test methods that use JdbcTemplate.
有两种方法可以对使用JdbcTemplate的方法进行单元测试。
We can use an in-memory database such as the H2 database as the data source for testing. However, in real-world applications, the SQL query could have complicated relationships, and we need to create complex setup scripts to test the SQL statements.
我们可以使用内存数据库,如H2数据库作为测试的数据源。然而,在现实世界的应用中,SQL查询可能有复杂的关系,我们需要创建复杂的设置脚本来测试SQL语句。
Alternatively, we can also mock the JdbcTemplate object to test the method functionality.
另外,我们也可以模拟JdbcTemplate 对象来测试方法的功能。
3. Unit Test With H2 Database
3.用H2数据库进行单元测试
We can create a data source that connects to the H2 database and inject it into the EmployeeDAO class:
我们可以创建一个连接到H2数据库的数据源,并将其注入EmployeeDAO类中:。
@Test
public void whenInjectInMemoryDataSource_thenReturnCorrectEmployeeCount() {
DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
.addScript("classpath:jdbc/schema.sql")
.addScript("classpath:jdbc/test-data.sql")
.build();
EmployeeDAO employeeDAO = new EmployeeDAO();
employeeDAO.setDataSource(dataSource);
assertEquals(4, employeeDAO.getCountOfEmployees());
}
In this test, we first construct a data source on the H2 database. During the construction, we execute schema.sql to create the EMPLOYEE table:
在这个测试中,我们首先在H2数据库上构建一个数据源。在构建过程中,我们执行schema.sql来创建EMPLOYEE表。
CREATE TABLE EMPLOYEE
(
ID int NOT NULL PRIMARY KEY,
FIRST_NAME varchar(255),
LAST_NAME varchar(255),
ADDRESS varchar(255)
);
Also, we run test-data.sql to add test data into the table:
同时,我们运行test-data.sql,将测试数据添加到表中。
INSERT INTO EMPLOYEE VALUES (1, 'James', 'Gosling', 'Canada');
INSERT INTO EMPLOYEE VALUES (2, 'Donald', 'Knuth', 'USA');
INSERT INTO EMPLOYEE VALUES (3, 'Linus', 'Torvalds', 'Finland');
INSERT INTO EMPLOYEE VALUES (4, 'Dennis', 'Ritchie', 'USA');
Then, we can inject this data source into the EmployeeDAO class and test the getCountOfEmployees method over the in-memory H2 database.
然后,我们可以将这个数据源注入EmployeeDAO类,并通过内存中的H2数据库测试getCountOfEmployees方法。
4. Unit Test With Mock Object
4.用模拟对象进行单元测试
We can mock the JdbcTemplate object so that we don’t need to run the SQL statement on a database:
我们可以模拟JdbcTemplate对象,这样我们就不需要在数据库中运行SQL语句:。
public class EmployeeDAOUnitTest {
@Mock
JdbcTemplate jdbcTemplate;
@Test
public void whenMockJdbcTemplate_thenReturnCorrectEmployeeCount() {
EmployeeDAO employeeDAO = new EmployeeDAO();
ReflectionTestUtils.setField(employeeDAO, "jdbcTemplate", jdbcTemplate);
Mockito.when(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM EMPLOYEE", Integer.class))
.thenReturn(4);
assertEquals(4, employeeDAO.getCountOfEmployees());
}
}
In this unit test, we first declare a mock JdbcTemplate object with the @Mock annotation. Then we inject it to the EmployeeDAO object using ReflectionTestUtils. Also, we use the Mockito utility to mock the return result of the JdbcTemplate query. This allows us to test the functionality of the getCountOfEmployees method without connecting to a database.
在这个单元测试中,我们首先用@Mock注解声明了一个模拟的JdbcTemplate对象。然后我们使用ReflectionTestUtils将其注入到EmployeeDAO对象。此外,我们使用Mockito工具来模拟JdbcTemplate查询的返回结果。这使我们能够测试getCountOfEmployees方法的功能,而无需连接到数据库。
We use an exact match on the SQL statement string when we mock the JdbcTemplate query. In real-world applications, we may create complex SQL strings, and it is hard to do an exact match. Therefore, we can also use the anyString() method to bypass the string check:
当我们模拟JdbcTemplate查询时,我们对SQL语句字符串使用精确匹配。在现实世界的应用中,我们可能会创建复杂的SQL字符串,而很难做到精确匹配。因此,我们也可以使用anyString()方法来绕过字符串检查。
Mockito.when(jdbcTemplate.queryForObject(Mockito.anyString(), Mockito.eq(Integer.class)))
.thenReturn(3);
assertEquals(3, employeeDAO.getCountOfEmployees());
5. Spring Boot @JdbcTest
5.Spring Boot @JdbcTest
Finally, if we’re using Spring Boot, there is an annotation we can use to bootstrap a test with an H2 database and a JdbcTemplate bean: @JdbcTest.
最后,如果我们使用Spring Boot,有一个注解,我们可以用H2数据库和JdbcTemplatebean来引导测试:@JdbcTest。
Let’s create a test class with this annotation:
让我们用这个注解创建一个测试类。
@JdbcTest
@Sql({"schema.sql", "test-data.sql"})
class EmployeeDAOIntegrationTest {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
void whenInjectInMemoryDataSource_thenReturnCorrectEmployeeCount() {
EmployeeDAO employeeDAO = new EmployeeDAO();
employeeDAO.setJdbcTemplate(jdbcTemplate);
assertEquals(4, employeeDAO.getCountOfEmployees());
}
}
We can also note the presence of the @Sql annotation which allows us to specify the SQL files to run before the test.
我们还可以注意到@Sql注解的存在,它允许我们指定测试前要运行的SQL文件。
6. Conclusion
6.结论
In this tutorial, we showed multiple ways to unit test JdbcTemplate.
在本教程中,我们展示了对JdbcTemplate进行单元测试的多种方法。
As always, the source code for the article is available over on GitHub.
一如既往,该文章的源代码可在GitHub上获得。