Skip to content
This repository was archived by the owner on Sep 1, 2023. It is now read-only.

Commit 166cf9b

Browse files
GH-15 - Add dedicated support for the Neo4j Test Harness.
This brings in a new module, `neo4j-java-driver-test-harness-spring-boot-autoconfigure`, that recognises both Neo4j 3.5 test harness (the default) and Neo4j 4.0 test harness. If it detects the test harness on the classpath and - if there's no explicitly configured driver instance - creates an instance of a testharness if there's none and an instance of the driver configured to use the new test harness or an existing test harness instance. The module defaults to 3.5.x so that it can stay on JDK 8. The examples - which had been JDK 11+ already - change the dependency to 4.0, so that there are tests in place for both scenarios. The module comes with documentation in form of the examples.
1 parent ba5f491 commit 166cf9b

File tree

16 files changed

+793
-79
lines changed

16 files changed

+793
-79
lines changed

README.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ The starter supports Neo4j server mode only, that is: A connection against a Neo
2727

2828
For a gentle introduction and some getting started guides, please use our
2929
link:docs/manual.adoc[Manual].
30+
The manual contains descriptions of all examples, which you'll find in the project source directory under https://github.com/neo4j/neo4j-java-driver-spring-boot-starter/tree/master/examples[examples].
Lines changed: 166 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,217 @@
11
== Testing against the Neo4j harness
22

3-
First of all, you have to include the test harness in your dependencies.
4-
Pick either community edition or enterprise edition.
3+
We provide a special module that brings in the community edition of the Neo4j harness
4+
and some additional utilities that hopefully make your life easier.
55

6-
Here's the community edition:
6+
[source,xml]
7+
.pom.xml
8+
----
9+
<dependency>
10+
<groupId>org.neo4j.driver</groupId>
11+
<artifactId>neo4j-java-driver-test-harness-spring-boot-autoconfigure</artifactId>
12+
<version>${neo4j-java-driver-spring-boot-starter.version}</version>
13+
<scope>test</scope>
14+
</dependency>
15+
----
16+
17+
If you need the enterprise edition, bring in the module like this:
718

819
[source,xml]
920
.pom.xml
1021
----
1122
<dependency>
12-
<groupId>org.neo4j.test</groupId>
13-
<artifactId>neo4j-harness</artifactId>
14-
<version>${neo4j.version}</version>
15-
<scope>test</scope>
23+
<groupId>org.neo4j.driver</groupId>
24+
<artifactId>neo4j-java-driver-test-harness-spring-boot-autoconfigure</artifactId>
25+
<version>${neo4j-java-driver-spring-boot-starter.version}</version>
26+
<scope>test</scope>
27+
<exclusions>
28+
<exclusion>
29+
<groupId>org.neo4j.test</groupId>
30+
<artifactId>neo4j-harness</artifactId>
31+
</exclusion>
32+
</exclusions>
33+
</dependency>
34+
<dependency>
35+
<groupId>com.neo4j.test</groupId>
36+
<artifactId>neo4j-harness-enterprise</artifactId>
37+
<version>${neo4j.version}</version>
38+
<scope>test</scope>
39+
<exclusions>
40+
<exclusion>
41+
<groupId>org.slf4j</groupId>
42+
<artifactId>slf4j-nop</artifactId>
43+
</exclusion>
44+
</exclusions>
1645
</dependency>
1746
----
1847

1948
That brings a ton of dependencies.
2049
The advantage of it: It starts very fast.
2150
If you don't want to have the dependencies and can live with a slower start, we recommend https://www.testcontainers.org/modules/databases/neo4j/[Testcontainers].
2251

23-
=== Starting up the Neo4j harness
52+
They are easy to use and can be configured as shown in <<option1,option 1 below>> as well.
53+
54+
=== Neo4j 3.5 or Neo4j 4.0?
55+
56+
Neo4j 3.5 and 4.0 have different requirements.
57+
Neo4j 4.0 requires at least JDK 11.
58+
We understand that not all of you are ready to go beyond JDK 8 (but you should).
59+
Therefore we decided to build the Test harness support by default against Neo4j 3.5 and JDK 8.
60+
61+
To use Neo4j 4.0 as in the following examples, please add this to your build file
62+
63+
[source,xml]
64+
.pom.xml
65+
----
66+
<dependencyManagement>
67+
<dependencies>
68+
<dependency>
69+
<groupId>org.neo4j.test</groupId>
70+
<artifactId>neo4j-harness</artifactId>
71+
<version>4.0.0</version>
72+
</dependency>
73+
</dependencies>
74+
</dependencyManagement>
75+
----
76+
77+
Be aware that the type of the 4.0 test harness is `org.neo4j.harness.Neo4j`.
78+
The following examples use 4.0 (`org.neo4j.harness.Neo4j`) but are applicable to `ServerControlls`, too.
79+
80+
=== Starting up the Neo4j harness and making Spring aware
2481

2582
There many different options.
26-
Here's a simple JUnit 5 variant:
83+
The main question is always: *How to make Spring Boot aware that it should use different configuration properties?*
84+
85+
[[option1]]
86+
==== Option 1: Add the embedded server as a Spring bean (recommended approach)
87+
88+
This is shown have this as `MoviesServiceAlt2Test`.
2789

2890
[source,java]
29-
.MoviesServiceTest.java
91+
[[simple-example]]
92+
.MoviesServiceAlt1Test.java
3093
----
31-
class MoviesServiceTest {
94+
@SpringBootTest
95+
class MoviesServiceAlt1Test {
96+
97+
@TestConfiguration // <1>
98+
static class TestHarnessConfig {
99+
100+
@Bean // <2>
101+
public Neo4j neo4j() {
102+
return Neo4jBuilders.newInProcessBuilder()
103+
.withDisabledServer() // No need for http
104+
.withFixture("CREATE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded', released:2003, tagline:'Free your mind'})")
105+
.build();
106+
107+
// For enterprise use
108+
// return com.neo4j.harness.EnterpriseNeo4jBuilders.newInProcessBuilder()
109+
// .newInProcessBuilder()
110+
// .build();
111+
}
112+
}
32113
33-
private static ServerControls embeddedDatabaseServer;
114+
@Test
115+
void testSomethingWithTheDriver(@Autowired Driver driver) {
116+
}
117+
}
118+
----
119+
<.> This is a test configuration only applicable for this test
120+
<.> This turns the embedded instance into a Spring Bean, bound to Springs lifecycle
34121

35-
@BeforeAll
36-
static void initializeNeo4j() {
37-
embeddedDatabaseServer = TestServerBuilders
38-
.newInProcessBuilder()
39-
.newServer();
122+
The autoconfiguration module for the test harness makes the starter aware of the harness and reconfigures the driver to use it.
123+
This would be the recommended way of doing things.
124+
125+
[[option2]]
126+
==== Option 2: Use the provided harness instance
127+
128+
`MoviesServiceAlt2Test.java` demonstrates the fully automatic configuration of test harness and driver:
129+
130+
[source,java]
131+
[[simple-example]]
132+
.MoviesServiceAlt2Test.java
133+
----
134+
@SpringBootTest
135+
public class MoviesServiceAlt2Test {
136+
137+
@BeforeEach
138+
void prepareDatabase(@Autowired Neo4j neo4j) { // <.>
139+
neo4j.defaultDatabaseService().executeTransactionally(
140+
"CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'})"
141+
);
40142
}
41143
42-
@AfterAll
43-
static void closeNeo4j() {
44-
embeddedDatabaseServer.close();
144+
@Test
145+
void testSomethingWithTheDriver(@Autowired Driver driver) {
45146
}
46147
}
47148
----
149+
<.> As you don't have access to the builder, you have to provide your fixtures through the embedded database service.
150+
151+
This may come in handy in some scenarios, but generally, using the builder API as shown above is preferable.
152+
On the plus side: The automatic configuration of the harness takes care of disabling the embedded webserver (for Neo4j 4.0+).
48153

49-
== Option a: Make Spring Boot aware of the URL of the embedded server
154+
[[option3]]
155+
==== Option 3: Start Neo4j outside Spring and apply its URL to configuration
50156

51-
In either case, the real issue you have to solve during testing is:
52-
*How to make Spring Boot aware that it should use different configuration properties?*
157+
Here we start the embedded instance from the JUnit 5 context and
158+
than use an `org.springframework.context.ApplicationContextInitializer` to apply `TestPropertyValues` to the Spring environment.
53159

54-
We recommend using a custom `org.springframework.context.ApplicationContextInitializer` on a `@SpringBootTest` like this:
160+
NOTE: You don't actually need `neo4j-java-driver-test-harness-spring-boot-autoconfigure` for this solution. It's enough to have the
161+
Test harness - either 3.5.x or 4.0.x or Community or enterprise edition on the classpath.
162+
If you have the test harness autoconfiguration support on the classpath, you have to explicitly disable it.
55163

56164
[source,java]
57165
[[simple-example]]
58-
.MoviesServiceTest.java
166+
.MoviesServiceAlt3Test.java
59167
----
60168
@SpringBootTest
169+
@EnableAutoConfiguration(exclude = { Neo4jTestHarnessAutoConfiguration.class }) // <.>
61170
@ContextConfiguration(initializers = { MoviesServiceTest.Initializer.class })
62-
class MoviesServiceTest {
171+
class MoviesServiceAlt3Test {
63172
64-
private static ServerControls embeddedDatabaseServer;
173+
private static Neo4j embeddedDatabaseServer;
174+
175+
@BeforeAll
176+
static void initializeNeo4j() { // <.>
177+
embeddedDatabaseServer = TestServerBuilders
178+
.newInProcessBuilder()
179+
.withDisabledServer() // <.>
180+
.withFixture("CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'})")
181+
.newServer();
182+
}
183+
184+
@AfterAll
185+
static void closeNeo4j() { // <.>
186+
embeddedDatabaseServer.close();
187+
}
65188
66189
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
67190
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
68191
69-
TestPropertyValues.of(
192+
TestPropertyValues.of( // <.>
70193
"org.neo4j.driver.uri=" + embeddedDatabaseServer.boltURI().toString(),
71194
"org.neo4j.driver.authentication.password="
72195
).applyTo(configurableApplicationContext.getEnvironment());
73196
}
74197
}
198+
199+
@Test
200+
void testSomethingWithTheDriver(@Autowired Driver driver) {
201+
}
75202
}
76203
----
204+
<.> Disable the autoconfiguration (only needed if you have `neo4j-java-driver-test-harness-spring-boot-autoconfigure` on the classpath)
205+
<.> Use a JUnit `BeforeAll` to boot Neo4j
206+
<.> The driver uses only the Bolt port, not the http port, so we don't need the embedded webserver (that option is only available in Neo4j Harness 4.0+)
207+
<.> Close it in an `AfterAll`
208+
<.> This the essential part: Apply the new configuration values
77209

78-
== Option b: Add your own driver bean to the context
210+
This is a good solution It works well with both Community and enterprise edition and decouples the creation of the server from configuring the client.
211+
The downside of it: You have to configure a lot of stuff manually and your mileage may vary.
79212

80-
We have this as `MoviesServiceAltTest`.
81-
While the configuration seems less complex, it changes more than just the url:
82-
Having a driver bean of your own in the context, disables the starter.
83-
That is of course ok, but you might end up with a very different configuration in test than in production.
84-
For example, you'll notice that in `MoviesServiceAltTest`, the driver does not use Slf4j logging, but it's own default.
213+
==== Running your own driver bean
85214

86-
Option a only adds properties with higher values onto the default ones.
87-
So, if you have configured more options of the driver in your `application.properties` or else, they still get applied.
88-
That is not the case for you own Driver bean.
215+
You can always fall back to create your own driver bean, but that actually disables the starter for the driver.
216+
That is of course ok, but you might end up with a very different configuration in test than in production.
217+
For example the driver will not use Spring logging, but its own default.

examples/testing-with-neo4j-harness/pom.xml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,33 @@
2121
<neo4j.version>4.0.0</neo4j.version>
2222
</properties>
2323

24+
<dependencyManagement>
25+
<dependencies>
26+
<dependency>
27+
<groupId>org.neo4j.test</groupId>
28+
<artifactId>neo4j-harness</artifactId>
29+
<version>${neo4j.version}</version>
30+
</dependency>
31+
</dependencies>
32+
</dependencyManagement>
33+
2434
<dependencies>
2535
<dependency>
2636
<groupId>org.neo4j.driver</groupId>
2737
<artifactId>neo4j-java-driver-spring-boot-starter</artifactId>
2838
<version>${neo4j-java-driver-spring-boot-starter.version}</version>
2939
</dependency>
3040
<dependency>
31-
<groupId>org.neo4j.test</groupId>
32-
<artifactId>neo4j-harness</artifactId>
33-
<version>${neo4j.version}</version>
41+
<groupId>org.neo4j.driver</groupId>
42+
<artifactId>neo4j-java-driver-test-harness-spring-boot-autoconfigure</artifactId>
43+
<version>${neo4j-java-driver-spring-boot-starter.version}</version>
3444
<scope>test</scope>
3545
</dependency>
3646
<dependency>
3747
<groupId>org.springframework.boot</groupId>
3848
<artifactId>spring-boot-starter</artifactId>
3949
</dependency>
50+
4051
<dependency>
4152
<groupId>org.springframework.boot</groupId>
4253
<artifactId>spring-boot-starter-test</artifactId>
@@ -98,7 +109,7 @@
98109
</property>
99110
</activation>
100111
<properties>
101-
<revision>4.0.0</revision>
112+
<revision>4.0</revision>
102113
</properties>
103114
</profile>
104115
<profile>
@@ -120,7 +131,7 @@
120131
</property>
121132
</activation>
122133
<properties>
123-
<changelist></changelist>
134+
<changelist>-SNAPSHOT</changelist>
124135
</properties>
125136
</profile>
126137
</profiles>

examples/testing-with-neo4j-harness/src/test/java/org/neo4j/doc/driver/springframework/boot/simple/MoviesServiceAltTest.java renamed to examples/testing-with-neo4j-harness/src/test/java/org/neo4j/doc/driver/springframework/boot/simple/MoviesServiceAlt1Test.java

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@
2020

2121
import static org.assertj.core.api.Assertions.*;
2222

23-
import org.junit.jupiter.api.AfterAll;
24-
import org.junit.jupiter.api.BeforeAll;
2523
import org.junit.jupiter.api.Test;
26-
import org.neo4j.driver.AuthTokens;
27-
import org.neo4j.driver.Driver;
28-
import org.neo4j.driver.GraphDatabase;
2924
import org.neo4j.harness.Neo4j;
3025
import org.neo4j.harness.Neo4jBuilders;
3126
import org.springframework.beans.factory.annotation.Autowired;
@@ -34,36 +29,26 @@
3429
import org.springframework.context.annotation.Bean;
3530

3631
/**
37-
* This variant uses a custom a completely, custom driver bean and effectively disables the starter.
32+
* This variant creates a custom instance of the test harness and exposing it as a bean. There are a couple of ways to do this,
33+
* this is just one of them. With `neo4j-java-driver-spring-boot-test-harness-4x-support` on the class path, the automatic configuration will pick this up.
34+
* <p>If you already have the harness support on the classpath, this would actually be the recommended version of doing things.
3835
*/
3936
@SpringBootTest
40-
class MoviesServiceAltTest {
41-
42-
private static Neo4j embeddedDatabaseServer;
43-
44-
@BeforeAll
45-
static void initializeNeo4j() {
46-
47-
embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder()
48-
.withFixture(""
49-
+ "CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'})\n"
50-
+ "CREATE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded', released:2003, tagline:'Free your mind'})\n"
51-
+ "CREATE (TheMatrixRevolutions:Movie {title:'The Matrix Revolutions', released:2003, tagline:'Everything that has a beginning has an end'})\n"
52-
)
53-
.build();
54-
}
55-
56-
@AfterAll
57-
static void closeNeo4j() {
58-
embeddedDatabaseServer.close();
59-
}
37+
class MoviesServiceAlt1Test {
6038

6139
@TestConfiguration
62-
static class Initializer {
40+
static class TestHarnessConfig {
6341

6442
@Bean
65-
public Driver driver() {
66-
return GraphDatabase.driver(embeddedDatabaseServer.boltURI(), AuthTokens.none());
43+
public Neo4j neo4j() {
44+
return Neo4jBuilders.newInProcessBuilder()
45+
.withDisabledServer() // No need for http
46+
.withFixture(""
47+
+ "CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'})\n"
48+
+ "CREATE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded', released:2003, tagline:'Free your mind'})\n"
49+
+ "CREATE (TheMatrixRevolutions:Movie {title:'The Matrix Revolutions', released:2003, tagline:'Everything that has a beginning has an end'})\n"
50+
)
51+
.build();
6752
}
6853
}
6954

0 commit comments

Comments
 (0)