TL;博士; 即可。我有一个动态创建新数据库表的方法,我想为它编写一个单元测试。不幸的是,测试运行器在测试后没有以适当的方式执行回滚,并且在测试完成后表仍然保留在DB中。我该怎么办?
我对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数据库,它不能被非关系型数据库所取代。
答案 0 :(得分:4)
首先,CREATE TABLE是一个DDL语句,而不是DML语句。这意味着回滚不会删除表。如果要清理数据库,则必须使用 // Do any additional setup after loading the view.
__block NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:@"Apple"];
[array addObject:@"Orange"];
[array addObject:@"Mango"];
[array addObject:@"Banana"];
But when I try to add object from JSONModelArray still showing the above 4 object only.
Here is JSONModelArray code:
//fetch the feed
_collectionBusinessFeeds = [[CollectionBusinessManager alloc] initFromURLWithString:@"http://localhost:8888/json/collectionBusinessFinal.json"
completion:^(JSONModel *model, JSONModelError *err) {
for(NSDictionary *item in _collectionBusinessFeeds.collectionBusinesses){
NSLog(@"%@",item);
NSString *title = [item valueForKey:@"name"];
[array addObject:title];
NSLog(@"%@",array);
// here array is printing all the objects with the above 4 objects
}
}];
或@After
方法明确删除它。
但是你真的需要在PostgreSQL数据库上进行测试吗? Spring对in memory databases提供了很好的支持,默认的嵌入式数据库是HSQL,它对postgresql语法有很好的支持。如果您没有复杂的声明,它就足够了,并且可以避免使主数据库混乱(可能是破坏性的)单元测试。
您可以使用@AfterClass
方法创建数据库。这是一个简单的例子:
@BeforeClass