我目前正在使用GraphUnit, Spock和一个正在处理的Neo4j服务器对我的Spring Data Neo4j 4.0支持的应用程序进行集成测试。
在我的测试操作之后,它是一个非常漂亮的工具,可以对图数据库的状态进行断言,但是我注意到,为了让GraphUnit的assertGraph
和printGraph
向我展示我所期望的,我的Neo4j事务必须首先提交。从逻辑上讲,这对我来说是有意义的,但这也意味着我不能将我的集成测试标记为@Transactional
,并且在一个测试中对进程数据库所做的任何数据更改都会影响到后续的测试。
我通过在Spock夹具方法中的每个测试方法后清除数据库来处理此问题,这工作得很好,但我非常希望能够:
- 设置一个测试Neo4j数据集ONCE
- 在每次测试后回滚测试方法更改
- 仍然可以使用GraphUnit的断言和打印工具
我的问题是——有没有一种方法可以同时实现这三个目标?如果我想使用GraphUnit,事务提交是一个潜在的要求/假设吗?
虽然您可以毫不费力地管理测试方法之间的Neo4j事务,但这里棘手的事情是让GraphUnit使用您的测试方法参与的相同事务来做出断言。
考虑到GraphUnit需要您使用GraphDatabaseService
,恐怕您最好的选择确实是为每个测试重新创建您的测试数据。
尽管如此,您可以通过使用可重用的JUnit测试规则来节省一些工作,因为它减少了为每个测试控制编写可拆卸方法的需要。在实现org.junit.rules.TestRule
的类中,您可以在其构造函数中设置GraphDatabaseService
,然后执行如下操作:
@Override
public Statement apply(final Statement baseStatement, Description description) {
setUpTestData();
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
if (graphDatabaseService.isAvailable(1000)) {
baseStatement.evaluate();
} else {
Assert.fail("Database was shut down or didn't become available within 1s");
}
} finally {
resetDatabase();
}
}
};
}
public void setUpTestData() {
// can set up common test data here, or just use an @Before method in the test harness
}
public void resetDatabase() {
this.graphDatabaseService.execute("MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE r, n");
}
你可以像这样包含它:
public class ArbitraryTest {
@Rule
public final Neo4jTestRule neo4jRule = new Neo4jTestRule();
@Test
public void arbitraryTestMethod() {
// some code...
GraphUnit.assertSameGraph(sameGraphCypher, neo4jRule.getGraphDatabaseService());
}
}
请注意,如果您将其包含为静态@ClassRule
,那么它将运行apply
方法只一次为整个测试类,这可以更有效,但您必须在@Before
/@After
方法中手动调用reset和setup方法来清理测试运行之间的东西。