使用 Java(Spring 框架)和内存数据库测试在 DAO 类 中找到的 CRUD 方法的正确方法是什么?
What is the correct way of testing CRUD methods that are found in DAO classes using Java(Spring framework) and In-memory DB?
我正在尝试编写好的集成测试用例以供练习。到目前为止,我已经为三种方法(save、findById 和 getAll 方法)实现了测试用例,但我忍不住认为我做错了。
下面是我目前的代码:
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {DatabaseConfigs.class})
public class UserDaoImplTest {
private DataSource dataSource;
private Connection con;
private UserDao userDao;
@Autowired
public UserDaoImplTest(@Qualifier("h2DataSource")DataSource dataSource) {
this.dataSource = dataSource;
userDao = new UserDaoImpl(dataSource);
}
@BeforeEach
public void setUp() throws SQLException {
con = dataSource.getConnection();
ScriptUtils.executeSqlScript(con, new ClassPathResource("config/schema.sql"));
ScriptUtils.executeSqlScript(con, new ClassPathResource("config/data.sql"));
}
@AfterEach
public void tearDown() throws SQLException {
con.close();
}
@Test
@DisplayName("Test to check if the created user, using save method, is present in db.")
public void testSave() throws SQLException {
User user = new User("luka", "pass");
userDao.save(user);
String sql = "SELECT name, password from user order by id desc";
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
boolean result = rs.next();
assertTrue(result, "Cant retrieve inserted user");
String name = rs.getString("name");
String password = rs.getString("password");
assertEquals("luka", name, "Retrieved username doesnt match.");
assertEquals("pass", password, "Retrieved password doesnt match.");
}
@Test
@DisplayName("Test to check if the getAll method is retrieving users from db.")
public void testGetAll() {
List<User> getAllUsers = userDao.getAll();
assertTrue(getAllUsers.size() > 0, "Size of retrieved users can't be 0");
}
@Test
@DisplayName("Test to check if the id of a retrived user matches the id supplied.")
public void testFindById() {
long id = 2;
Optional<User> userOpt = userDao.findById(id);
assertTrue(userOpt.isPresent(), "No user retrieved");
User user = userOpt.get();
assertEquals(2, user.getId(), "Retrieved id of a user doesnt match the expected id.");
}
@Test
public void testDelete() {
fail("Not yet implemented");
}
@Test
public void testUpdate() {
fail("Not yet implemented");
}
}
例如,我想知道我是否可以像这样为保存方法编写测试:
private int getMaxId() throws SQLException {
String sql = "SELECT max(id) as id from user";
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
rs.next();
int id = rs.getInt("id");
ps.close();
rs.close();
return id;
}
@Test
@DisplayName("Test to check if the created user, using save method, is present in db.")
public void testSave() throws SQLException {
User user = new User("luka", "pass");
userDao.save(user);
Optional<User> userOpt = userDao.findById(getMaxId());
assertTrue(userOpt.isPresent,"Can't retrieve user.")
assertTrue(result, "Cant retrieve inserted user");
String name = rs.getString("name");
String password = rs.getString("password");
assertEquals("luka", name, "Retrieved username doesnt match.");
assertEquals("pass", password, "Retrieved password doesnt match.");
}
在这种情况下,我正在使用 findById 方法测试保存方法,所以我基本上是在一个测试用例中测试两种方法。这是进行测试的好方法吗,因为我认为我打破了方法隔离的规则?我想知道测试这些方法的最佳方法是什么。感谢任何帮助,如果我的代码不好,请告诉我我做错了什么。
我相信您会得到一些不同的答案。对我来说,虽然我想要一个测试来确保与数据库的集成是好的:
- 启动数据库(提示:docker 通常有帮助)
- 将数据库置于已知状态(加载测试数据)
- 调用执行某些 CRUD 操作的方法
- 做出一些断言
您可能听说过一个术语,如果您可以 insert/update/delete 一些数据然后尝试使用您的 Read 方法(来自 cRud)读回它,您将完成“往返”检查.
假设一切顺利,你会得到你期望的结果(更新结果(forinsert/update),或者一个空集(用于删除),或者可能是一个异常)。
如果您使用构建工具(我的首选 gradle 与 maven 但两者都应该有效)来管理启动容器的过程,它也会有所帮助。签出 https://www.testcontainers.org/ or https://github.com/avast/gradle-docker-compose-plugin(使用 gradle 构建工具)
我正在尝试编写好的集成测试用例以供练习。到目前为止,我已经为三种方法(save、findById 和 getAll 方法)实现了测试用例,但我忍不住认为我做错了。
下面是我目前的代码:
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {DatabaseConfigs.class})
public class UserDaoImplTest {
private DataSource dataSource;
private Connection con;
private UserDao userDao;
@Autowired
public UserDaoImplTest(@Qualifier("h2DataSource")DataSource dataSource) {
this.dataSource = dataSource;
userDao = new UserDaoImpl(dataSource);
}
@BeforeEach
public void setUp() throws SQLException {
con = dataSource.getConnection();
ScriptUtils.executeSqlScript(con, new ClassPathResource("config/schema.sql"));
ScriptUtils.executeSqlScript(con, new ClassPathResource("config/data.sql"));
}
@AfterEach
public void tearDown() throws SQLException {
con.close();
}
@Test
@DisplayName("Test to check if the created user, using save method, is present in db.")
public void testSave() throws SQLException {
User user = new User("luka", "pass");
userDao.save(user);
String sql = "SELECT name, password from user order by id desc";
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
boolean result = rs.next();
assertTrue(result, "Cant retrieve inserted user");
String name = rs.getString("name");
String password = rs.getString("password");
assertEquals("luka", name, "Retrieved username doesnt match.");
assertEquals("pass", password, "Retrieved password doesnt match.");
}
@Test
@DisplayName("Test to check if the getAll method is retrieving users from db.")
public void testGetAll() {
List<User> getAllUsers = userDao.getAll();
assertTrue(getAllUsers.size() > 0, "Size of retrieved users can't be 0");
}
@Test
@DisplayName("Test to check if the id of a retrived user matches the id supplied.")
public void testFindById() {
long id = 2;
Optional<User> userOpt = userDao.findById(id);
assertTrue(userOpt.isPresent(), "No user retrieved");
User user = userOpt.get();
assertEquals(2, user.getId(), "Retrieved id of a user doesnt match the expected id.");
}
@Test
public void testDelete() {
fail("Not yet implemented");
}
@Test
public void testUpdate() {
fail("Not yet implemented");
}
}
例如,我想知道我是否可以像这样为保存方法编写测试:
private int getMaxId() throws SQLException {
String sql = "SELECT max(id) as id from user";
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
rs.next();
int id = rs.getInt("id");
ps.close();
rs.close();
return id;
}
@Test
@DisplayName("Test to check if the created user, using save method, is present in db.")
public void testSave() throws SQLException {
User user = new User("luka", "pass");
userDao.save(user);
Optional<User> userOpt = userDao.findById(getMaxId());
assertTrue(userOpt.isPresent,"Can't retrieve user.")
assertTrue(result, "Cant retrieve inserted user");
String name = rs.getString("name");
String password = rs.getString("password");
assertEquals("luka", name, "Retrieved username doesnt match.");
assertEquals("pass", password, "Retrieved password doesnt match.");
}
在这种情况下,我正在使用 findById 方法测试保存方法,所以我基本上是在一个测试用例中测试两种方法。这是进行测试的好方法吗,因为我认为我打破了方法隔离的规则?我想知道测试这些方法的最佳方法是什么。感谢任何帮助,如果我的代码不好,请告诉我我做错了什么。
我相信您会得到一些不同的答案。对我来说,虽然我想要一个测试来确保与数据库的集成是好的:
- 启动数据库(提示:docker 通常有帮助)
- 将数据库置于已知状态(加载测试数据)
- 调用执行某些 CRUD 操作的方法
- 做出一些断言
您可能听说过一个术语,如果您可以 insert/update/delete 一些数据然后尝试使用您的 Read 方法(来自 cRud)读回它,您将完成“往返”检查.
假设一切顺利,你会得到你期望的结果(更新结果(forinsert/update),或者一个空集(用于删除),或者可能是一个异常)。
如果您使用构建工具(我的首选 gradle 与 maven 但两者都应该有效)来管理启动容器的过程,它也会有所帮助。签出 https://www.testcontainers.org/ or https://github.com/avast/gradle-docker-compose-plugin(使用 gradle 构建工具)