gpt4 book ai didi

java - 如何为动态创建数据库表的方法编写单元测试?

转载 作者:行者123 更新时间:2023-12-01 18:12:12 25 4
gpt4 key购买 nike

tl;博士;。我有一种动态创建新数据库表的方法,我想为其编写一个单元测试。不幸的是,测试运行程序在测试后没有以正确的方式执行回滚,并且测试完成后该表仍然保留在数据库中。我该怎么办?

长话短说:

我对 Java Persistence 和 Java Spring 都不是很熟悉,所以,如果您发现当前的解决方案丑陋(对我来说,它相当丑陋),请告诉我如何改进它 - 我会的非常感谢您的意见。

我有一个 SysDatastoreService ,它具有以下 addStaticDatastore 方法的实现。

@Service
public class SysDatastoreServiceImpl implements SysDatastoreService {
@Autowired
private SysDatastoreRepository datastoreRepository;

@Autowired
private DataSource dataSource;

@Override
@Transactional
public Optional<SysDatastore> addStaticDatastore(String name, String tableName, String ident, Long ord) {
String createTableSql = PostgresTableSqlBuilder.createTableInPublicSchemaWithBigintPkAndFkId(
tableName,
SysObject.TABLE_NAME,
Optional.of(SysObject.ID_COLUMN_NAME)).buildSql();

Optional<SysDatastore> sysDatastore = Optional.empty();

try(
Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()
) {
connection.setAutoCommit(false);
Savepoint beforeTableCreation = connection.setSavepoint();

try {
statement.execute(createTableSql);
sysDatastore = Optional.ofNullable(
datastoreRepository.save(new SysDatastore(name, tableName, DatastoreType.STATIC, ident, ord)));
} catch(SQLException e) {
e.printStackTrace();
}

if(!sysDatastore.isPresent()) {
connection.rollback(beforeTableCreation);
} else {
connection.commit();
}
} catch(SQLException e1) {
e1.printStackTrace();
}

return sysDatastore;
}
}

因此,如您所见,我从 DataSource 收到新连接并尝试创建新表。如果成功,我将在 SysDataStoreRepository 中创建一个新条目,如果失败,我将回滚表创建。

当前方法有一些缺点,其中之一是表创建和条目插入在单独的连接上操作(我说得对吗?)。

但是我在编写单元测试时遇到了一些问题。这是我尝试过的:

@Transactional(propagation = Propagation.REQUIRED)
@RunWith(SpringJUnit4ClassRunner.class)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/rest-servlet.xml")
public class SysDatastoreServiceTest {
@Autowired
private SysDatastoreService sysDatastoreService;

@Autowired
private DataSource dataSource;

@Test
public void testAddStaticDatastore() throws Exception {
Optional<SysDatastore> sysDatastore =
sysDatastoreService.addStaticDatastore("New static datastore", "new_datastore_table",
"NEW_DATASTORE_TABLE", 42L);

assertTrue(sysDatastore.isPresent());
assertEquals("New static datastore", sysDatastore.get().getName());
assertEquals("NEW_DATASTORE_TABLE", sysDatastore.get().getIdent());
assertEquals("new_datastore_table", sysDatastore.get().getTableName());
assertEquals(DatastoreType.STATIC, sysDatastore.get().getDynType());
assertEquals(42L, sysDatastore.get().getOrd().longValue());

assertTrue(dataSource.getConnection()
.getMetaData()
.getTables(null, null, sysDatastore.get().getTableName(), null)
.next());
}

这个测试看起来很简单:我只需比较所有字段,然后检查数据库中是否有新表。

但是,当我运行两次或更多次时,此测试会失败。查看数据库时,我注意到表 new_datastore_table 仍然保留在架构中。我猜想,由于手写事务和原始sql执行,它没有正确回滚,但我不确定。

问题:我应该如何以正确的方式为此方法编写测试用例?如果当前的做法从根本上来说是错误的,那么应该如何改变?

旁注:我使用的是PostgreSQL数据库,不能用非关系型数据库替换。

最佳答案

首先,CREATE TABLE 是一条 DDL 语句,而不是 DML 语句。这意味着回滚不会删除该表。如果您想清理数据库,则必须在 @After@AfterClass 方法中显式删除它。

但是您真的需要在 PostgreSQL 数据库上进行测试吗? Spring对in memory databases有很大的支持默认的嵌入式数据库是HSQL,它对postgresql语法有很好的支持。如果您没有复杂的语句,那么它就足够了,并且可以避免使(可能具有破坏性的)单元测试的主数据库变得困惑。

您可以在@BeforeClass方法中创建数据库。这是一个过于简单的示例:

private static DriverManagerDataSource dataSource;

@BeforeClass
public static void setupClass() throws Exception {
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.addScript(new ClassPathResource("path/to/package/defaults.sql"));
dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:hsqldb:mem:pgtest;sql.syntax_pgs=true");
dataSource.setUsername("SA");

Connection con = dataSource.getConnection();
assertNotNull(con);
populator.populate(con);
con.close();
}

关于java - 如何为动态创建数据库表的方法编写单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32137131/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com