什么是 Testcontainers
Testcontainers 是一个开源库,它允许您测试任何容器化的依赖项,例如数据库、各种云技术或消息代理。为便于使用,Testcontainers 提供了许多称为模块的预配置依赖项。
除此之外,Testcontainers 支持多种语言,您可以使用这些语言轻松编写测试,例如 Python、Go、Rust、Ruby、JavaScript、.NET、Java 等。
Testcontainers 的常见用例
得益于容器技术,您可以在无需复杂设置的情况下获得全新的、干净的实例,适用于以下用例:
- 数据访问层集成测试
- UI/验收测试
- 应用程序集成测试
使用 Podman 设置 Testcontainers
开始之前,您需要安装 Podman 并在套接字监听模式下运行它。
$ podman system service --time=0 &
通过以下选项之一将 Testcontainers 运行时设置为 Podman:
-
启用 Docker 兼容性 功能。
-
在您的主目录中创建一个
.testcontainers.properties
文件,用于 Testcontainers 的全局配置,并将以下行添加到该配置文件中:-
macOS
docker.host=unix://$(podman machine inspect --format '{{.ConnectionInfo.PodmanSocket.Path}}')
配置后运行以下命令:
$ export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock
-
Linux
docker.host=unix://${XDG_RUNTIME_DIR}/podman/podman.sock
注意Testcontainers 支持的每种语言都有不同的属性受 .testcontainers.properties 文件支持。
-
可选: 如果您以无根模式(rootless mode)运行 Podman,则必须通过定义以下环境变量来禁用 Ryuk:
$ export TESTCONTAINERS_RYUK_DISABLED=true
创建项目
本示例使用 Testcontainers 的 Redis 服务和 Redis 模块。您可以按照以下步骤创建一个项目并安装所有依赖项。
-
初始化一个项目。
$ npm init -y
-
安装依赖项。
$ npm install testcontainers vitest @testcontainers/redis redis typescript --save-dev
-
更新
package.json
文件。package.json...
"scripts": {
"test": "vitest"
},
... -
使用 Redis Node.js 库创建基本的 CRUD 操作。
index.tsimport { createClient, RedisClientType } from 'redis';
let redisClient: RedisClientType | undefined = undefined;
export async function connectRedis(url: string) {
redisClient = createClient({ url });
await redisClient.connect();
return redisClient;
}
export async function setValue(key: string, value: string): Promise<string | null> {
if (!redisClient) {
throw new Error('Redis client is not connected');
}
return await redisClient.set(key, value);
}
export async function getValue(key: string): Promise<string | null> {
if (!redisClient) {
throw new Error('Redis client is not connected');
}
return redisClient.get(key);
}
export async function deleteValue(key: string[]): Promise<number> {
if (!redisClient) {
throw new Error('Redis client is not connected');
}
return await redisClient.del(key);
}
export async function disconnectRedis() {
if (redisClient) {
await redisClient.quit();
redisClient = undefined;
}
} -
为 CRUD 操作创建基本测试。
index.spec.tsimport { afterAll, beforeAll, beforeEach, expect, test } from 'vitest';
import { connectRedis, deleteValue, disconnectRedis, getValue, setValue } from '.';
import { RedisContainer, StartedRedisContainer } from '@testcontainers/redis';
import { Wait } from 'testcontainers';
import { createClient } from 'redis';
let container: StartedRedisContainer;
beforeAll(async () => {
container = await new RedisContainer()
.withExposedPorts(6379)
.withWaitStrategy(Wait.forLogMessage('Ready to accept connections'))
.start();
await connectRedis(`redis://:${container.getMappedPort(6379)}`);
});
afterAll(async () => {
await disconnectRedis();
});
beforeEach(async () => {
// Flushind DB and adding to Redis some values before each test
const client = createClient({ url: `redis://:${container.getMappedPort(6379)}` });
await client.connect();
await client.flushDb();
await client.set('preset-key', 'preset-value');
await client.set('preset-key1', 'preset-value1');
await client.quit();
});
test('set value on server', async () => {
// Set value
const ret = await setValue('key', 'value');
expect(ret).toBe('OK');
// Update value
const ret1 = await setValue('key', 'updated-value');
expect(ret1).toBe('OK');
});
test('get value from server', async () => {
// Get preset value
const value = await getValue('preset-key');
expect(value).toBe('preset-value');
// Get not existing value
const value1 = await getValue('key');
expect(value1).toBeNull();
});
test('delete value on server', async () => {
// Delete two records in a same time
const res = await deleteValue(['preset-key', 'preset-key1']);
expect(res).toBe(2);
// Delete not existing record
const res1 = await deleteValue(['key']);
expect(res1).toBe(0);
});
运行测试
首次运行 Testcontainers 时,请确保使用以下命令在 DEBUG
模式下运行测试:
$ DEBUG=testcontainers* npm test
然后,您应该能看到类似下面的行:
testcontainers [DEBUG] Loading ".testcontainers.properties" file...
testcontainers [DEBUG] Loaded ".testcontainers.properties" file
testcontainers [DEBUG] Found custom configuration: dockerHost: "unix:///run/user/1000//podman/podman.sock
这些行表明 Testcontainers 找到了配置文件,并且容器是在 Podman 引擎上而不是 Docker 上创建的。
结论
本教程提供了一个基本的分步演练,使用 Testcontainers 技术通过 Podman 运行 Redis 服务器。更多示例可以在 Testcontainers 的指南中找到。如果您遇到任何问题,请随时在 Podman Desktop 的 GitHub 上提出问题。