5
votes

Problem

I build an application using a Neo4j database. I like to test some custom Cypher queries using Spring Boot's @DataNeo4jTest annotation (see also Spring Boot Test - Neo4j), but I run in either one of the following problems:

  • The test tries to connect to a Neo4j instance using the BOLT driver.
  • The test fails to load the embedded driver.

Details

My dependencies are managed with Maven following the Spring Data Neo4j Reference Documentation. Section 10.3.1 of the SDN documentation explains:

By default, SDN will use the BOLT driver to connect to Neo4j and you don’t need to declare it as a separate dependency in your pom. If you want to use the embedded or HTTP drivers in your production application, you must add the following dependencies as well. (This dependency on the embedded driver is not required if you only want to use the embedded driver for testing. See the section on Testing below for more information).

Therefore, the relevant parts of my pom.xml are:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi=...>
    ...
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        ...
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-neo4j</artifactId>
        </dependency>
        <dependency>
            <groupId>org.neo4j.test</groupId>
            <artifactId>neo4j-harness</artifactId>
            <version>3.3.4</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    ...
</project>

My main/resources/application.yml is:

spring:
    data:
        neo4j:
            uri: bolt://localhost
            username: <username>
            password: <password>

My test/resources/application.yml is:

spring.data.neo4j.uri: file:///neo4j.db

Without the test/resources/application.yml I get the following exception, which I assume is caused by using the BOLT driver:

org.springframework.transaction.CannotCreateTransactionException: Could not open Neo4j Session for transaction;
    nested exception is org.neo4j.driver.v1.exceptions.AuthenticationException: The client is unauthorized due to authentication failure.

With the test/resources/application.yml I get the following exception:

java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'neo4jAuditionBeanFactoryPostProcessor': Unsatisfied dependency expressed through constructor parameter 0;
    nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.class]: Bean instantiation via factory method failed;
    nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.neo4j.ogm.session.SessionFactory]: Factory method 'sessionFactory' threw exception;
    nested exception is org.neo4j.ogm.exception.core.ConfigurationException: Could not load driver class org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver

Questions

  • Are there any dependencies missing?
  • Is the configuration wrong?
  • Does anyone have a link to a working example using the Spring Boot annotation @DataNeo4jTest?

Any suggestion is welcome.

2

2 Answers

5
votes

I have found a solution to my problem. It seems as if the BOLT driver is used as default for testing as well - which is confusing given the Spring Data Neo4j (SDN) documentation. Finally, the pom.xml of the GitHub project movies-java-spring-data-neo4j helped me. I added the following test dependency to my pom.xml:

<dependency>
    <groupId>org.neo4j</groupId>
    <artifactId>neo4j-ogm-embedded-driver</artifactId>
    <version>${neo4j-ogm.version}</version>
    <scope>test</scope>
</dependency>

I kept the test/resources/application.yml but removed the line:

spring.data.neo4j.uri: file:///neo4j.db

Now, the test context starts with the embedded driver, and creates a temporary database file like file:/C:/Users/Me/AppData/Local/Temp/neo4j.db6943517458205762238/, which is awesome. I can get a clean database instance for every test method.

I hope this answer will help others, who have the same problem. I'm happy to provide more details if necessary.

1
votes

@DataNeo4JTest works great with Spring Boot 2.x.

Example Test:

@RunWith(SpringRunner.class)
@DataNeo4jTest
public class WidgetRepositoryTest {

  @Autowired
  private WidgetRepository repository;

  private Widget widget;

  @Before
  public void setUp() {
    widget = WidgetTestData.builder().build();
  }

  @Test
  public void itShouldSaveAndRetrieve() {

    final Widget saved = repository.save(widget);
    assertThat(saved.getId()).isNotNull();
    assertThat(saved.getName()).isEqualTo(widget.getName());

    final Optional<Widget> found = repository.findById(saved.getId());
    assertThat(found).hasValueSatisfying(w-> {
      assertThat(w.getId()).isEqualTo(saved.getId());
      assertThat(w.getName()).isEqualTo(saved.getName());
    });
  }
}

The Neo4J-related dependencies in my Maven POM:

<dependency>
  <groupId>org.neo4j.test</groupId>
  <artifactId>neo4j-harness</artifactId>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.neo4j</groupId>
  <artifactId>neo4j-ogm-embedded-driver</artifactId>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>