1. Overview
1.概述
Testcontainers is a Java library for creating temporary Docker containers for unit testing purposes. It’s useful when we want to avoid testing with actual servers.
Testcontainers是一个Java库,用于创建用于单元测试的临时Docker容器。当我们想避免使用实际的服务器进行测试时,它很有用。
In this tutorial, we’ll learn how to use Testcontainers while testing a Spring Boot application that uses Redis.
在本教程中,我们将学习如何在测试使用Redis的Spring Boot应用程序时使用Testcontainers。
2. Project Setup
2.项目设置
The first prerequisite to using any test container is to have Docker installed on the machine where we are running the tests.
使用任何测试容器的第一个先决条件是在我们运行测试的机器上安装Docker。
Once we have Docker installed, we can start setting up our Spring Boot application.
一旦我们安装了Docker,我们就可以开始设置我们的Spring Boot应用程序。
In this application, we’ll set up a Redis hash, a repository, and a service that will use the repository to interact with Redis.
在这个应用程序中,我们将设置一个Redis哈希值、一个存储库和一个将使用存储库与Redis交互的服务。
2.1. Dependencies
2.1. 依赖性
Let’s start by adding the required dependencies to our project.
让我们开始向我们的项目添加所需的依赖项。
Firstly, we’ll add the Spring Boot Starter Test and Spring Boot Starter Data Redis dependencies:
首先,我们将添加Spring Boot Starter Test和Spring 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>
Next, let’s add the Testcontainers dependency:
接下来,让我们添加Testcontainers依赖性。
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.17.2</version>
<scope>test</scope>
</dependency>
2.2. Autoconfiguration
2.2.自动配置
Since we don’t require any advanced configurations, we can use autoconfiguration to set up a connection to the Redis server.
由于我们不需要任何高级配置,我们可以使用自动配置来设置与Redis服务器的连接。
For this, we need to add the Redis connection details to the application.properties file:
为此,我们需要在application.properties文件中添加Redis连接细节。
spring.redis.host=127.0.0.1
spring.redis.port=6379
3. Application Setup
3.应用设置
Let’s start with the code for our main application. We’ll build a small application that reads and writes products to a Redis database.
让我们从我们的主应用程序的代码开始。我们将建立一个小的应用程序,将产品读写到Redis数据库。
3.1. Entity
3.1. 实体
Let’s start with the Product class:
让我们从产品类开始:
@RedisHash("product")
public class Product implements Serializable {
private String id;
private String name;
private double price;
// Constructor, getters and setters
}
The @RedisHash annotation is used to tell Spring Data Redis that this class should be stored in a Redis hash. Saving as a hash is good for entities that don’t contain nested objects.
@RedisHash注解用于告诉Spring Data Redis,该类应存储在Redis哈希中。以哈希形式保存对于不包含嵌套对象的实体来说是很好的。
3.2. Repository
3.2.存储库
Next, we can define a repository for our Product hash:
接下来,我们可以为我们的产品哈希定义一个存储库:
@Repository
public interface ProductRepository extends CrudRepository<Product, String> {
}
The CRUD repository interface already implements the methods we need to save, update, delete and find products. So we don’t need to define any methods ourselves.
CRUD资源库接口已经实现了我们需要的保存、更新、删除和查找产品的方法。所以我们不需要自己定义任何方法。
3.3. Service
3.3.服务
Finally, let’s create a service that performs read and write operations using the ProductRepository:
最后,让我们创建一个服务,使用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
}
This service can then be used by controllers or services to perform CRUD operations on the products.
然后,这个服务可以被控制器或服务用来对产品执行CRUD操作。
In actual applications, these methods may contain more complex logic, but for the purposes of this tutorial, we’ll only focus on the Redis interactions.
在实际应用中,这些方法可能包含更复杂的逻辑,但为了本教程的目的,我们将只关注Redis的交互。
4. Testing
4.测试
We’ll now write tests for our ProductService to test the CRUD operations.
现在我们将为我们的ProductService编写测试,以测试CRUD操作。
4.1. Testing the Service
4.1.测试该服务
Let’s write an integration test for the ProductService:
让我们为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());
}
This assumes that a Redis database is running on the URL specified in the properties. If we don’t have a Redis instance running or our server cannot connect to it, the tests will run into errors.
这假定 Redis 数据库正在属性中指定的 URL 上运行。如果我们没有运行 Redis 实例,或者我们的服务器无法连接到它,测试将出现错误。
4.2. Starting a Redis Container With Testcontainers
4.2.用Testcontainers启动一个Redis容器
Let’s solve this problem by running a Redis test container when the tests are run. Then, we’ll change the connection details from the code itself.
让我们通过在运行测试时运行一个Redis测试容器来解决这个问题。然后,我们将从代码本身改变连接细节。
Let’s look at the code to create and run the test container:
让我们看一下创建和运行测试容器的代码。
static {
GenericContainer<?> redis =
new GenericContainer<>(DockerImageName.parse("redis:5.0.3-alpine")).withExposedPorts(6379);
redis.start();
}
Let’s understand the different parts of this code:
让我们了解一下这段代码的不同部分。
- we have created a new container from the image redis:5.0.3-alpine
- by default, the Redis instance will run on port 6379. To expose this port, we can use the withExposedPorts() method. It’ll expose this port and map it to a random port on the host machine
- the start() method will start the container and wait for it to be ready
- we have added this code to a static code block so that it runs before the dependencies are injected, and tests are run
4.3. Changing the Connection Details
4.3.改变连接细节
At this point, we have a Redis container running, but we haven’t changed the connection details used by the application. To do this, all we need to do is to override the connection details in the application.properties file using system properties:
在这一点上,我们有一个Redis容器在运行,但我们还没有改变应用程序使用的连接细节。要做到这一点,我们需要做的就是使用系统属性覆盖application.properties文件中的连接细节。
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());
}
We’ve set the spring.redis.host property to the IP address of the container.
我们已经将spring.redis.host属性设置为容器的 IP 地址。
We can get the mapped port of port 6379 to set the spring.redis.port property.
我们可以获取端口6379的映射端口来设置spring.redis.port属性。
Now when the tests run, they’ll connect to the Redis database running on the container.
现在,当测试运行时,它们将连接到容器上运行的Redis数据库。
5. Conclusion
5.总结
In this article, we learned how to use Redis Testcontainer to run the tests. We also looked at certain aspects of Spring Data Redis to understand how to use it.
在这篇文章中,我们学习了如何使用Redis Testcontainer来运行测试。我们还研究了Spring Data Redis的某些方面,以了解如何使用它。
As always, the source code for the examples can be found over on GitHub.
一如既往,这些例子的源代码可以在GitHub上找到。