使用 Spring Boot 和 @DataNeo4jTest

Spring Boot 透過 org.springframework.boot:spring-boot-starter-test 提供了 @DataNeo4jTest。後者引入了 org.springframework.boot:spring-boot-test-autoconfigure,其中包含該註解和所需的底層程式碼。

在 Maven 構建中包含 Spring Boot Starter Test
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
在 Gradle 構建中包含 Spring Boot Starter Test
dependencies {
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

@DataNeo4jTest 是一個 Spring Boot 測試切片。該測試切片提供了使用 Neo4j 進行測試所需的所有基礎架構:一個事務管理器、一個客戶端、一個模板和宣告的倉庫,具體是命令式還是響應式變體,取決於是否存在響應式依賴。該測試切片已經包含了 @ExtendWith(SpringExtension.class),因此它可以自動與 JUnit 5 (JUnit Jupiter) 一起執行。

@DataNeo4jTest 預設提供了命令式和響應式兩種基礎架構,並且還隱含地包含了 @Transactional。然而,Spring 測試中的 @Transactional 始終意味著命令式事務,因為宣告式事務需要方法的返回型別來決定是需要命令式 PlatformTransactionManager 還是響應式 ReactiveTransactionManager

要斷言響應式倉庫或服務的正確事務行為,您需要將 TransactionalOperator 注入到測試中,或者將您的領域邏輯包裝在服務中,這些服務使用帶有註解的方法,這些方法公開了返回型別,使得基礎設施可以選擇正確的事務管理器。

測試切片不引入嵌入式資料庫或任何其他連線設定。您需要使用適當的連線。

我們推薦兩種選擇之一:要麼使用 Neo4j Testcontainers 模組,要麼使用 Neo4j 測試工具。雖然 Testcontainers 是一個著名的專案,擁有許多不同服務的模組,但 Neo4j 測試工具卻鮮為人知。它是一個嵌入式例項,在測試儲存過程時特別有用,如 測試您的基於 Neo4j 的 Java 應用程式 中所述。但是,測試工具也可以用於測試應用程式。由於它在與您的應用程式相同的 JVM 中啟動資料庫,因此效能和時間可能與您的生產設定不相似。

為了您的方便,我們提供了三種可能的場景:Neo4j test harness 3.5 和 4.x/5.x 以及 Testcontainers Neo4j。我們為 3.5 和 4.x/5.x 提供了不同的示例,因為這些版本之間的測試工具發生了變化。此外,4.0 需要 JDK 11。

使用 Neo4j test harness 3.5 的 @DataNeo4jTest

您需要以下依賴項才能執行 使用 Neo4j 3.5 test harness

Neo4j 3.5 test harness 依賴項
<dependency>
    <groupId>org.neo4j.test</groupId>
    <artifactId>neo4j-harness</artifactId>
    <version>3.5.33</version>
    <scope>test</scope>
</dependency>

Neo4j 3.5 企業版的依賴項位於 com.neo4j.test:neo4j-harness-enterprise 下,並需要適當的倉庫配置。

使用 Neo4j 3.5 test harness
import static org.assertj.core.api.Assertions.assertThat;

import java.util.Optional;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.neo4j.harness.ServerControls;
import org.neo4j.harness.TestServerBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;

@DataNeo4jTest
class MovieRepositoryTest {

	private static ServerControls embeddedDatabaseServer;

	@BeforeAll
	static void initializeNeo4j() {

		embeddedDatabaseServer = TestServerBuilders.newInProcessBuilder() (1)
			.newServer();
	}

	@AfterAll
	static void stopNeo4j() {

		embeddedDatabaseServer.close(); (2)
	}

	@DynamicPropertySource  (3)
	static void neo4jProperties(DynamicPropertyRegistry registry) {

		registry.add("spring.neo4j.uri", embeddedDatabaseServer::boltURI);
		registry.add("spring.neo4j.authentication.username", () -> "neo4j");
		registry.add("spring.neo4j.authentication.password", () -> null);
	}

	@Test
	public void findSomethingShouldWork(@Autowired Neo4jClient client) {

		Optional<Long> result = client.query("MATCH (n) RETURN COUNT(n)")
			.fetchAs(Long.class)
			.one();
		assertThat(result).hasValue(0L);
	}
}
1 建立嵌入式 Neo4j 的入口點
2 這是一個 Spring Boot 註解,允許動態註冊應用程式屬性。我們覆蓋了相應的 Neo4j 設定。
3 在所有測試後關閉 Neo4j。

使用 Neo4j test harness 4.x/5.x 的 @DataNeo4jTest

您需要以下依賴項才能執行 使用 Neo4j 4.x/5.x test harness

Neo4j 4.x test harness 依賴項
<dependency>
    <groupId>org.neo4j.test</groupId>
    <artifactId>neo4j-harness</artifactId>
    <version>4.4.25</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Neo4j 4.x/5.x 企業版的依賴項位於 com.neo4j.test:neo4j-harness-enterprise 下,並需要適當的倉庫配置。

使用 Neo4j 4.x/5.x test harness
import static org.assertj.core.api.Assertions.assertThat;

import java.util.Optional;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.neo4j.harness.Neo4j;
import org.neo4j.harness.Neo4jBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;

@DataNeo4jTest
class MovieRepositoryTest {

	private static Neo4j embeddedDatabaseServer;

	@BeforeAll
	static void initializeNeo4j() {

		embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder() (1)
			.withDisabledServer() (2)
			.build();
	}

	@DynamicPropertySource (3)
	static void neo4jProperties(DynamicPropertyRegistry registry) {

		registry.add("spring.neo4j.uri", embeddedDatabaseServer::boltURI);
		registry.add("spring.neo4j.authentication.username", () -> "neo4j");
		registry.add("spring.neo4j.authentication.password", () -> null);
	}

	@AfterAll
	static void stopNeo4j() {

		embeddedDatabaseServer.close(); (4)
	}

	@Test
	public void findSomethingShouldWork(@Autowired Neo4jClient client) {

		Optional<Long> result = client.query("MATCH (n) RETURN COUNT(n)")
			.fetchAs(Long.class)
			.one();
		assertThat(result).hasValue(0L);
	}
}
1 建立嵌入式 Neo4j 的入口點
2 停用不需要的 Neo4j HTTP 伺服器
3 這是一個 Spring Boot 註解,允許動態註冊應用程式屬性。我們覆蓋了相應的 Neo4j 設定。
4 在所有測試後關閉 Neo4j。

使用 Testcontainers Neo4j 的 @DataNeo4jTest

當然,使用 Testcontainers 配置連線的原則與 使用 Test containers 中所示的相同。您需要以下依賴項

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

以及一個完整的測試

使用 Test containers
import static org.assertj.core.api.Assertions.assertThat;

import java.util.Optional;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.neo4j.Neo4jContainer;

@DataNeo4jTest
class MovieRepositoryTCTest {

	private static Neo4jContainer neo4jContainer;

	@BeforeAll
	static void initializeNeo4j() {

		neo4jContainer = new Neo4jContainer()
			.withAdminPassword("somePassword");
		neo4jContainer.start();
	}

	@AfterAll
	static void stopNeo4j() {

		neo4jContainer.close();
	}

	@DynamicPropertySource
	static void neo4jProperties(DynamicPropertyRegistry registry) {

		registry.add("spring.neo4j.uri", neo4jContainer::getBoltUrl);
		registry.add("spring.neo4j.authentication.username", () -> "neo4j");
		registry.add("spring.neo4j.authentication.password", neo4jContainer::getAdminPassword);
	}

	@Test
	public void findSomethingShouldWork(@Autowired Neo4jClient client) {

		Optional<Long> result = client.query("MATCH (n) RETURN COUNT(n)")
			.fetchAs(Long.class)
			.one();
		assertThat(result).hasValue(0L);
	}
}

@DynamicPropertySource 的替代方案

在某些情況下,上述註解不適合您的用例。其中一種情況可能是您希望 100% 控制驅動程式的初始化方式。在執行測試容器的情況下,您可以使用像這樣的巢狀靜態配置類來實現這一點

@TestConfiguration(proxyBeanMethods = false)
static class TestNeo4jConfig {

    @Bean
    Driver driver() {
        return GraphDatabase.driver(
        		neo4jContainer.getBoltUrl(),
        		AuthTokens.basic("neo4j", neo4jContainer.getAdminPassword())
        );
    }
}

如果您想使用屬性但不能使用 @DynamicPropertySource,您可以使用初始化器

動態屬性的替代注入
@ContextConfiguration(initializers = PriorToBoot226Test.Initializer.class)
@DataNeo4jTest
class PriorToBoot226Test {

    private static Neo4jContainer neo4jContainer;

    @BeforeAll
    static void initializeNeo4j() {

        neo4jContainer = new Neo4jContainer()
            .withAdminPassword("somePassword");
        neo4jContainer.start();
    }

    @AfterAll
    static void stopNeo4j() {

        neo4jContainer.close();
    }

    static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertyValues.of(
                "spring.neo4j.uri=" + neo4jContainer.getBoltUrl(),
                "spring.neo4j.authentication.username=neo4j",
                "spring.neo4j.authentication.password=" + neo4jContainer.getAdminPassword()
            ).applyTo(configurableApplicationContext.getEnvironment());
        }
    }
}
© . This site is unofficial and not affiliated with VMware.