0

I am trying to run some tests in the same class using Neo4jRule to initialize the graph. Using @Rule for Neo4jRule variable, @Before and @After methods, the initialization runs before each test. I want the initialization to run once for all tests. I know that I can use annotations @ClassRule for Neo4jRule variable, @BeforeClass and @AfterClass and make all of them static, but I get the message:

java.lang.IllegalStateException: Cannot access instance URI before or after the test runs.

at org.neo4j.harness.junit.Neo4jRule.boltURI(Neo4jRule.java:154)
at FullTextIndexTest.before(FullTextIndexTest.java:65)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

The line 65 at the 2nd version of code is:

driver = GraphDatabase.driver(
            neo4j.boltURI(),
            Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig()
    );

Which is the right way to initialize once the graph? Ideally, I would like to have the code in one class and use it in many test classes.


Code using @Rule, @Before and @After:

@Rule
public Neo4jRule neo4j;
private Driver driver;
private Session session;

public FullTextIndexTest() {
    InputStream resource = this.getClass().getResourceAsStream("/graph.cypher");
    StringBuilder cypher = new StringBuilder();
    Scanner scanner = new Scanner(resource).useDelimiter("\n");
    while (scanner.hasNext()) {
        cypher.append(scanner.next()).append("\n");
    }
    neo4j = new Neo4jRule().withFixture(cypher.toString());
}

@Before
public void before() {
    driver = GraphDatabase.driver(
            neo4j.boltURI(),
            Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig()
    );
    session = driver.session();
    // Start indexing
    GraphDatabaseService db = neo4j.getGraphDatabaseService();
    try (org.neo4j.graphdb.Transaction tx = db.beginTx()) {
        // Index nodes
        Index<Node> ftiNodes = db.index().forNodes(NODES_INDEX, FULL_TEXT);
        ResourceIterable<Node> allNodes = db.getAllNodes();
        for (Node node : allNodes) {
            // Index all node's properties
            Map<String, Object> allProperties = node.getAllProperties();
            for (Map.Entry<String, Object> property : allProperties.entrySet()) {
                ftiNodes.add(node, property.getKey(), property.getValue());
            }
        }
        tx.success();
    }

    try (org.neo4j.graphdb.Transaction tx = db.beginTx()) {
        // Index relationships
        RelationshipIndex ftiRels = db.index().forRelationships(RELS_INDEX, FULL_TEXT);
        ResourceIterable<Relationship> allRelationships = db.getAllRelationships();
        for (Relationship relationship : allRelationships) {
            Map<String, Object> allProperties = relationship.getAllProperties();
            for (Map.Entry<String, Object> property : allProperties.entrySet()) {
                ftiRels.add(relationship, property.getKey(), property.getValue());
            }
        }

        tx.success();
    }
}

@After
public void after() {
    driver.close();
}

Code using @ClassRule, @BeforeClass and @AfterClass:

@ClassRule
public static Neo4jRule neo4j;
private static Driver driver;
private static Session session;

@BeforeClass
public static void before() {
    InputStream resource = FullTextIndexTest.class.getResourceAsStream("/graph.cypher");
    StringBuilder cypher = new StringBuilder();
    Scanner scanner = new Scanner(resource).useDelimiter("\n");
    while (scanner.hasNext()) {
        cypher.append(scanner.next()).append("\n");
    }
    neo4j = new Neo4jRule().withFixture(cypher.toString());
    driver = GraphDatabase.driver(
            neo4j.boltURI(),
            Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig()
    );
    session = driver.session();
    // Start indexing
    GraphDatabaseService db = neo4j.getGraphDatabaseService();
    try (org.neo4j.graphdb.Transaction tx = db.beginTx()) {
        // Index nodes
        Index<Node> ftiNodes = db.index().forNodes(NODES_INDEX, FULL_TEXT);
        ResourceIterable<Node> allNodes = db.getAllNodes();
        for (Node node : allNodes) {
            // Index all node's properties
            Map<String, Object> allProperties = node.getAllProperties();
            for (Map.Entry<String, Object> property : allProperties.entrySet()) {
                ftiNodes.add(node, property.getKey(), property.getValue());
            }
        }
        tx.success();
    }

    try (org.neo4j.graphdb.Transaction tx = db.beginTx()) {
        // Index relationships
        RelationshipIndex ftiRels = db.index().forRelationships(RELS_INDEX, FULL_TEXT);
        ResourceIterable<Relationship> allRelationships = db.getAllRelationships();
        for (Relationship relationship : allRelationships) {
            Map<String, Object> allProperties = relationship.getAllProperties();
            for (Map.Entry<String, Object> property : allProperties.entrySet()) {
                ftiRels.add(relationship, property.getKey(), property.getValue());
            }
        }

        tx.success();
    }
}

@AfterClass
public static void after() {
    driver.close();
}
Aris F.
  • 1,105
  • 1
  • 11
  • 27

1 Answers1

0

The problem was the initialization of static neo4j variable in the @BeforeClass public static void before() method. The correct method is to use a static initializer block.

Wrong:

@ClassRule
public static Neo4jRule neo4j;
private static Driver driver;

@BeforeClass
public static void before() {
    // Read you resource file (named cypher here)
    neo4j = new Neo4jRule().withFixture(cypher);
    driver = GraphDatabase.driver(
            neo4j.boltURI(),
            Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig()
    );
    // rest of your code
}

@AfterClass
public static void after() {
    driver.close();
}    

Correct

@ClassRule
public static Neo4jRule neo4j;
private static Driver driver;

static {
    // Read you resource file (named cypher here)
    neo4j = new Neo4jRule().withFixture(cypher);
}

@BeforeClass
public static void before() {
    driver = GraphDatabase.driver(
            neo4j.boltURI(),
            Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig()
    );
    // rest of your code
}

@AfterClass
public static void after() {
    driver.close();
}
Aris F.
  • 1,105
  • 1
  • 11
  • 27