Testing APOC inside your Stored Procedures

The Awesome Procedures on Cypher (APOC) plugin is packed with goodies to make your life working with Neo4j easier. Sometimes you want to use these goodies in your own stored procedures…and you want to be able to test them. So how do we go about doing that exactly?

The first thing you’ll want to do is include APOC in your pom.xml file. Make sure you use a version that is appropriate for the Neo4j version you are using.

        <!-- Awesome Procedures on Cypher -->

Notice the scope is just “test” because we assume you’ll have the actual APOC jar in the plugins folder of your Neo4j database.

For this example, we’ll use “apoc.load.xml” to seed some sample data into our stored procedure tests. I have the XML file in “resources/data/catalog/weapon.xml” as shown below:

In the real procedure I expect the xml file to be in the Neo4j “import” folder which means we can just grab it via “file:///weapons.xml”. For testing however we don’t really get a chance to copy this file over to the in memory TestServer that gets built. To get around this, we’ll put in a test parameter and get the file from the resources folder if it’s set.

    @Procedure(name = "com.maxdemarzi.seed.catalog", mode = Mode.WRITE)
    @Description("CALL com.maxdemarzi.seed.catalog(test)")
    public Stream<StringResult> seedCatalog(@Name(value = "test", defaultValue = "") String test) {

        String weaponsXML;

        if (test.isEmpty()){
            weaponsXML = "file:///weapons.xml";
        } else {
            ClassLoader classLoader = ClassLoader.getSystemClassLoader();
            weaponsXML = classLoader.getResource("data/catalog/weapons.xml").getFile();

        HashMap<String, Object> weapons = new HashMap<>();
        weapons.put("file", weaponsXML);
        weapons.put("path", "/chummer/weapons/weapon");

With that figured out we can use the apoc procedure inside of ours. For example:

  db.execute("CALL apoc.load.xml($file, $path) YIELD value " +
                        "WITH [attr IN value._children WHERE attr._text <> '' |  [attr._type, attr._text]] AS pairs " +
                        "WITH apoc.map.fromPairs(pairs) AS value " +
                        "CREATE (w:Product) " +
                        "SET w += value " +
                        "WITH w, value " +
                        "MATCH (c:Category {name: value.category}) " +
                        "CREATE (w)-[:IN_CATEGORY]->(c) ", weapons);

Now on to our tests. When we build the TestServer, we can add the apoc classes that we are using. In this example we are using both the apoc.load.Xml.class for apoc.load.xml and apoc.map.Maps.class for apoc.map.fromPairs. Notice one is a Procedure and the other is a Function. Lastly we want to set the “apoc.import.file.enabled” setting to “true” in order to import data.

public class ExampleTest {
    private static ServerControls neo4j;

    static void startNeo4j() {
        neo4j = TestServerBuilders.newInProcessBuilder()
                .withConfig("apoc.import.file.enabled", "true")

If you don’t like adding the test parameter to your stored procedures and still need to distinguish between file locations, you can just get the class loader inside the Test itself and pass in the file as a parameter instead. See this example on our Neo4j Community site from David Allen.

public void testLoadJson() throws Exception {
		URL url = ClassLoader.getSystemResource("map.json");
		testCall(db, "CALL apoc.load.json({url})",map("url",url.toString()),

Pretty neat right? I’ve found the APOC import procedures extremely valuable when creating large amounts of test data for our stored procedure tests.

Tagged , , , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: