知識庫 / Spring / Spring Boot RSS 訂閱

Spring Boot 中使用 Testcontainers 測試 Redis

Spring Boot,Testing
HongKong
4
11:59 AM · Dec 06 ,2025

1. 概述

Testcontainers 是一個用於創建臨時 Docker 容器以進行單元測試的 Java 庫。它在我們需要避免使用實際服務器進行測試時非常有用。

在本教程中,我們將學習如何在測試使用 Redis 的 Spring Boot 應用程序時使用 Testcontainers。

2. 項目設置

使用任何測試容器的前提是,必須在運行測試的機器上安裝 Docker。

安裝 Docker 後,我們就可以開始設置我們的 Spring Boot 應用程序。

在應用程序中,我們將設置一個 Redis 哈希、一個倉庫(repository)和一個服務,該服務將使用倉庫與 Redis 進行交互。

2.1. 依賴項

首先,我們需要為項目添加所需的依賴項。

首先,我們將添加以下依賴項:Spring Boot Starter TestSpring Boot Starter Data Redis

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

接下來,讓我們添加 Testcontainers 依賴項:

<dependency> 
    <groupId>org.testcontainers</groupId> 
    <artifactId>testcontainers</artifactId> 
    <version>1.19.7</version> 
    <scope>test</scope> 
</dependency>

2.2. 自動配置

由於我們不需要進行任何高級配置,因此可以使用自動配置來建立與 Redis 服務器的連接。

為此,我們需要將 Redis 連接詳細信息添加到 application.properties 文件中:

spring.redis.host=127.0.0.1
spring.redis.port=6379

3. 應用程序設置

我們首先開始編寫主應用程序的代碼。我們將構建一個小型應用程序,該應用程序能夠讀取和寫入產品信息到 Redis 數據庫。

3.1. 實體

讓我們從 產品 類開始:

@RedisHash("product")
public class Product implements Serializable {
    private String id;
    private String name;
    private double price;

    // Constructor, getters and setters
}

@RedisHash 註解用於告知 Spring Data Redis 此類應存儲在 Redis 哈希中。將實體存儲為哈希對於不包含嵌套對象的實體來説是有效的。

3.2. 倉庫

接下來,我們可以為我們的 產品 哈希定義一個倉庫:

@Repository
public interface ProductRepository extends CrudRepository<Product, String> {
}

CRUD 倉庫接口已經實現了我們需要的保存、更新、刪除和查找產品的方法。因此,我們無需自行定義任何方法。

3.3. 服務

最後,我們創建一個服務,該服務使用 ProductRepository 執行讀取和寫入操作:

@Service
public class ProductService {

    private final ProductRepository productRepository;

    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public Product getProduct(String id) {
        return productRepository.findById(id).orElse(null);
    }

    // other methods
}

此服務可供控制器或服務使用,以對產品執行 CRUD 操作。

在實際應用中,這些方法可能包含更復雜的邏輯,但對於本教程的目的,我們將僅關注 Redis 交互。

4. 測試

我們將為我們的 ProductService 編寫測試,以測試 CRUD 操作。

4.1. 測試服務

讓我們為 ProductService 編寫一個集成測試。

@Test
void givenProductCreated_whenGettingProductById_thenProductExistsAndHasSameProperties() {
    Product product = new Product("1", "Test Product", 10.0);
    productService.createProduct(product);
    Product productFromDb = productService.getProduct("1");
    assertEquals("1", productFromDb.getId());
    assertEquals("Test Product", productFromDb.getName());
    assertEquals(10.0, productFromDb.getPrice());
}

這假設 Redis 數據庫正在指定在屬性中 URL 上運行。如果未運行 Redis 實例或我們的服務器無法連接到它,則測試將遇到錯誤。

4.2. 使用 Testcontainers 啓動 Redis 容器

我們通過在測試運行時運行 Redis 測試容器來解決這個問題。然後,我們將從代碼本身更改連接詳細信息。

讓我們看一下創建和運行測試容器的代碼:

static {
    GenericContainer<?> redis = 
      new GenericContainer<>(DockerImageName.parse("redis:5.0.3-alpine")).withExposedPorts(6379);
    redis.start();
}

讓我們來理解這段代碼的不同部分:

  • 我們創建了一個新的容器,使用鏡像 redis:5.0.3-alpine
  • 默認情況下,Redis 實例將在端口 6379 上運行。要暴露此端口,可以使用 withExposedPorts() 方法。 這會暴露該端口並將它映射到主機機器上的一個隨機端口
  • start() 方法將啓動容器並等待其準備就緒
  • 我們已將此代碼添加到靜態代碼塊中,以便在注入依賴項和運行測試之前運行它

4.3. 修改連接信息

此時,我們已經啓動了一個 Redis 容器,但尚未修改應用程序使用的連接信息。要做到這一點,我們只需要通過使用系統屬性,在 <em >application.properties</em > 文件中覆蓋連接信息:

static {
    GenericContainer<?> redis = 
      new GenericContainer<>(DockerImageName.parse("redis:5.0.3-alpine")).withExposedPorts(6379);
    redis.start();
    System.setProperty("spring.redis.host", redis.getHost());
    System.setProperty("spring.redis.port", redis.getMappedPort(6379).toString());
}

我們已將 spring.redis.host 屬性設置為容器的 IP 地址。

我們可以通過獲取映射端口 6379 來設置 spring.redis.port 屬性。

現在,當測試運行時,它們將連接到容器上運行的 Redis 數據庫。

4.4. 使用 Redis 容器的替代配置

或者,我們可以通過使用 @Testcontainers 註解,在 Jupiter 集成中管理 Redis 容器的生命週期。 使用這種集成時,可以使用 @Container 註解來標記容器進行生命週期管理。 讓我們採用這種方法來配置 Redis 容器用於我們的測試。

首先,我們需要在項目的 pom.xml 文件中添加 junit-jupitertestcontainers-redis-junit-jupiter 依賴項:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>1.17.6</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>com.redis.testcontainers</groupId>
    <artifactId>testcontainers-redis-junit-jupiter</artifactId>
    <version>1.4.6</version>
    <scope>test</scope>
</dependency>

接下來,讓我們定義靜態字段 REDIS_CONTAINER,並使用 @Container 註解:

@Container
private static final RedisContainer REDIS_CONTAINER = 
  new RedisContainer(DockerImageName.parse("redis:5.0.3-alpine")).withExposedPorts(6379);

需要注意的是,被定義為靜態字段的容器將在測試方法之間共享,並且只會被啓動一次。

此外,讓我們使用 @DynamicPropertySource 註解定義 registerRedisProperties() 方法,以配置應用程序的連接屬性

@DynamicPropertySource
private static void registerRedisProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.redis.host", REDIS_CONTAINER::getHost);
    registry.add("spring.redis.port", () -> REDIS_CONTAINER.getMappedPort(6379).toString());
}

最後,讓我們驗證我們的配置是否按預期工作:

@Test
void givenRedisContainerConfiguredWithDynamicProperties_whenCheckingRunningStatus_thenStatusIsRunning() {
    assertTrue(REDIS_CONTAINER.isRunning());
}

太好了!我們可以看到 Redis 容器已準備好用於測試方法。此外,我們無需修改其他測試方法,可以像它們原本的樣子使用它們。

5. 結論

在本文中,我們學習瞭如何使用 Redis Testcontainer 運行測試。我們還探討了 Spring Data Redis 的某些方面,以瞭解如何使用它。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.