我正在利用以下技术堆栈
spring-boot : 3.0.0
JUnit5
H2(In-Memory)
问题在于,即使测试完成后,数据仍然保留在数据库中。
我尝试在测试完成后使用 JUnit 5 的扩展来清理数据库内容。
但是,在执行测试时,我观察到
registMemberTestIfEveryThingsIsOk
方法中保存的数据仍然存在,导致 registMemberTestIfOauthPlatformHasInvalidValue
方法中的第二个断言抛出异常不会抛出任何内容。
@SpringBootTest
@ExtendWith(DataClearExtension.class)
class AuthServiceTest {
@Autowired
private AuthService authService;
@BeforeAll
public static void initDataBase(@Autowired DataSource dataSource) {
try (Connection conn = dataSource.getConnection()) {
ScriptUtils.executeSqlScript(conn, new ClassPathResource("/sql/member_test.sql"));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
...
@Nested
class registMemberTest {
@ParameterizedTest
@CsvSource(value = {"123, google, yongjun, 213, kevinH, 20000928, male, student, red, img",
"2, kakao, hannah, 314, alex, 19980512, female, engineer, blue, img",
"3, apple, david, 415, emma, 20010320, male, designer, green, img",
"4, kakao, sarah, 516, michael, 19991225, female, developer, yellow, img",
"5, google, emily, 617, chris, 19921005, female, manager, orange, img"})
void registMemberTestIfDuplicatedIdExist(@AggregateWith(MemberAggregator.class) MemberRegistRequestDto memberRegistRequestDto) {
assertThrows(DataIntegrityViolationException.class, () -> authService.registMember(memberRegistRequestDto));
Member member = authService.findMemberByOAuthId(memberRegistRequestDto.oauthId());
assertAll(
() -> assertNotEquals(memberRegistRequestDto.name(), member.getName()),
() -> assertNotEquals(memberRegistRequestDto.nickname(), member.getNickname()),
() -> assertNotEquals(memberRegistRequestDto.birth(), member.getBirth())
);
}
@ParameterizedTest
@CsvSource(value = {"101, naver, yongjun, 213, kevin, 20000928, male, student, red, img",
"102, git, hannah, 314, alex, 19980512, female, engineer, blue, img",
"103, microsoft, david, 415, emma, 20010320, male, designer, green, img",
"104, samsung, sarah, 516, michael, 19991225, female, developer, yellow, img",
"105, wooabros, emily, 617, chris, 19921005, female, manager, orange, img"})
void registMemberTestIfoauthPlatformHasInvalidValue(@AggregateWith(MemberAggregator.class) MemberRegistRequestDto memberRegistRequestDto) {
assertAll(
() -> assertThrows(UnknownOAuthPlatformException.class, () -> authService.registMember(memberRegistRequestDto)),
//the error ocurred here!
() -> assertThrows(MemberSigninException.class, () -> authService.findMemberByOAuthId(memberRegistRequestDto.oauthId()))
);
}
}
...
static class MemberAggregator implements ArgumentsAggregator {
@Override
public Object aggregateArguments(ArgumentsAccessor argumentsAccessor, ParameterContext parameterContext) throws ArgumentsAggregationException {
return new MemberRegistRequestDto(argumentsAccessor.getString(0), argumentsAccessor.getString(1), argumentsAccessor.getString(2), argumentsAccessor.getString(3),
argumentsAccessor.getString(4), argumentsAccessor.getInteger(5), argumentsAccessor.getString(6), argumentsAccessor.getString(7), argumentsAccessor.getString(8),
argumentsAccessor.getString(9));
}
}
}
CREATE TABLE member
(
id BIGINT NOT NULL AUTO_INCREMENT,
oauth_id VARCHAR(255) NOT NULL,
oauth_platform ENUM ('APPLE', 'GOOGLE', 'KAKAO'),
name VARCHAR(255) NOT NULL,
profile_img VARCHAR(255),
nickname VARCHAR(255) NOT NULL,
birth INT,
gender VARCHAR(255),
profession VARCHAR(255),
signature_color VARCHAR(255) NOT NULL,
create_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_modified_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY oauth_id (oauth_id)
);
INSERT INTO member (oauth_id, oauth_platform, name, profile_img, nickname, birth, gender, profession, signature_color)
VALUES ('123', 'GOOGLE', 'hong', '123123', 'kevin', '0928', 'male', 'student', 'red'),
('2', 'GOOGLE', 'muny', '123123', 'anna', '0929', 'female', 'developer', 'blue'),
('3', 'GOOGLE', 'kim', '123123', 'jenny', '0930', 'female', 'professor', 'black'),
('4', 'GOOGLE', 'karina', '123123', 'katarina', '1000', 'female', 'developer', 'pink'),
('5', 'GOOGLE', 'down', '123123', 'mark', '1001', 'female', 'teacher', 'skyblue');
public class DataClearExtension implements BeforeEachCallback {
@Override
public void beforeEach(ExtensionContext extensionContext) throws Exception {
DataCleaner dataCleaner = getDataCleaner(extensionContext);
dataCleaner.clear();
}
private DataCleaner getDataCleaner(ExtensionContext extensionContext) {
return SpringExtension.getApplicationContext(extensionContext)
.getBean(DataCleaner.class);
}
}
@Component
public class DataCleaner {
private static final String FOREIGN_KEY_CHECK_FORMAT = "SET FOREIGN_KEY_CHECKS %d";
private static final String TRUNCATE_FORMAT = "TRUNCATE TABLE %s";
private final List<String> tableNames = new ArrayList<>();
@PersistenceContext
private EntityManager entityManager;
@PostConstruct
public void findDatabaseTableNames() {
List<Object[]> tableInfos = entityManager.createNativeQuery("SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA='PUBLIC'").getResultList();
for (Object[] tableInfo : tableInfos) {
String tableName = (String) tableInfo[0];
tableNames.add(tableName);
}
}
@Transactional
public void clear() {
entityManager.clear();
truncate();
}
private void truncate() {
entityManager.createNativeQuery(String.format(FOREIGN_KEY_CHECK_FORMAT, 0)).executeUpdate();
for (String tableName : tableNames) {
entityManager.createNativeQuery(String.format(TRUNCATE_FORMAT, tableName)).executeUpdate();
}
entityManager.createNativeQuery(String.format(FOREIGN_KEY_CHECK_FORMAT, 1)).executeUpdate();
}
spring:
datasource :
url: jdbc:h2:mem:test;MODE=MySQL
driverClassName: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: none
调试后发现
findDatabaseTableNames
类中的DataCleaner
方法无法获取表名,因为tableInfo的大小为0。
因此,我认为问题可能在于无法从 H2 检索表。但是,如果我在其他地方犯了任何其他错误,请告诉我。
我读过的文档
希望您度过愉快的一天。感谢您阅读长文。
尝试添加注解@TestInstance(TestInstance.Lifecycle.PER_CLASS)并将@BerforeAll方法转换为非静态并添加@AfterAll方法,如下所示:
@SpringBootTest
@ExtendWith(DataClearExtension.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class AuthServiceTest {
@Autowired
private AuthService authService;
@BeforeAll
public void initDataBase(@Autowired DataSource dataSource) {
try (Connection conn = dataSource.getConnection()) {
ScriptUtils.executeSqlScript(conn, new ClassPathResource("/sql/member_test.sql"));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@AfterAll
public void cleanUpDataBase(@Autowired DataSource dataSource) {
// clean up code goes here
}
@Nested
class registMemberTest {
@ParameterizedTest
@CsvSource(value = {"123, google, yongjun, 213, kevinH, 20000928, male, student, red, img",
"2, kakao, hannah, 314, alex, 19980512, female, engineer, blue, img",
"3, apple, david, 415, emma, 20010320, male, designer, green, img",
"4, kakao, sarah, 516, michael, 19991225, female, developer, yellow, img",
"5, google, emily, 617, chris, 19921005, female, manager, orange, img"})
void registMemberTestIfDuplicatedIdExist(@AggregateWith(MemberAggregator.class) MemberRegistRequestDto memberRegistRequestDto) {
assertThrows(DataIntegrityViolationException.class, () -> authService.registMember(memberRegistRequestDto));
Member member = authService.findMemberByOAuthId(memberRegistRequestDto.oauthId());
assertAll(
() -> assertNotEquals(memberRegistRequestDto.name(), member.getName()),
() -> assertNotEquals(memberRegistRequestDto.nickname(), member.getNickname()),
() -> assertNotEquals(memberRegistRequestDto.birth(), member.getBirth())
);
}
@ParameterizedTest
@CsvSource(value = {"101, naver, yongjun, 213, kevin, 20000928, male, student, red, img",
"102, git, hannah, 314, alex, 19980512, female, engineer, blue, img",
"103, microsoft, david, 415, emma, 20010320, male, designer, green, img",
"104, samsung, sarah, 516, michael, 19991225, female, developer, yellow, img",
"105, wooabros, emily, 617, chris, 19921005, female, manager, orange, img"})
void registMemberTestIfoauthPlatformHasInvalidValue(@AggregateWith(MemberAggregator.class) MemberRegistRequestDto memberRegistRequestDto) {
assertAll(
() -> assertThrows(UnknownOAuthPlatformException.class, () -> authService.registMember(memberRegistRequestDto)),
//the error ocurred here!
() -> assertThrows(MemberSigninException.class, () -> authService.findMemberByOAuthId(memberRegistRequestDto.oauthId()))
);
}
}
...
static class MemberAggregator implements ArgumentsAggregator {
@Override
public Object aggregateArguments(ArgumentsAccessor argumentsAccessor, ParameterContext parameterContext) throws ArgumentsAggregationException {
return new MemberRegistRequestDto(argumentsAccessor.getString(0), argumentsAccessor.getString(1), argumentsAccessor.getString(2), argumentsAccessor.getString(3),
argumentsAccessor.getString(4), argumentsAccessor.getInteger(5), argumentsAccessor.getString(6), argumentsAccessor.getString(7), argumentsAccessor.getString(8),
argumentsAccessor.getString(9));
}
}
}