Khai phá sức mạnh của Testcontainers: Kiểm thử linh hoạt, ổn định và hiệu quả
Trong bài viết này, tôi sẽ giúp các bạn khám phá về sức mạnh của Testcontainers, các khái niệm, định nghĩa liên quan để giúp bạn hiểu rõ hơn về nó. Hãy cùng bắt đầu nhé!
Testcontainers là gì?
Testcontainers là một thư viện mã nguồn mở phổ biến, cho phép các lập trình viên chạy các container nhẹ, tạm thời để kiểm thử tích hợp. Nó cung cấp các thành phần phụ thuộc thực tế như cơ sở dữ liệu, message broker (trình môi giới tin nhắn) và trình duyệt bên trong Docker container, đảm bảo tính nhất quán giữa các môi trường khác nhau.
Trải nghiệm của tôi với Testcontainers
Trong thực tế, tôi đã sử dụng Testcontainers trong một dự án TypeScript với Selenium và Cucumber để tăng độ tin cậy của kiểm thử và tối ưu hóa quá trình thực thi trong Bitbucket CI/CD pipeline.
Với Testcontainers cho Selenium, tôi có thể:
- Chạy kiểm thử trình duyệt Chrome trong môi trường container hóa.
- Đảm bảo mỗi lần chạy kiểm thử đều có một phiên trình duyệt sạch và mới.
- Ghi lại quá trình kiểm thử dưới dạng video MP4 để hỗ trợ debug khi kiểm thử thất bại.
- Tích hợp dễ dàng với CI/CD pipeline, duy trì tính nhất quán giữa các môi trường khác nhau.
Bây giờ, hãy cùng tìm hiểu cách Testcontainers hoạt động và tại sao nó lại là một công cụ thay đổi cuộc chơi trong kiểm thử tích hợp!
Tại sao QA Engineers yêu thích Testcontainers?
Testcontainers cung cấp một môi trường kiểm thử ổn định và thực tế, giúp loại bỏ các thiết lập kiểm thử không đáng tin cậy. Thay vì sử dụng mock hoặc giải pháp trong bộ nhớ (in-memory), QA engineers có thể tận dụng các dịch vụ thực tế chạy trong container độc lập.
Lợi ích chính:
- Môi trường kiểm thử ổn định: Đảm bảo mỗi lần kiểm thử đều bắt đầu từ trạng thái sạch, giúp giảm thiểu lỗi kiểm thử không ổn định.
- Kiểm thử với các thành phần phụ thuộc thực tế: Không cần dùng mock, bạn có thể kiểm thử với cơ sở dữ liệu, message broker, và trình duyệt thực tế.
- Kiểm thử giao diện trên nhiều trình duyệt: Hỗ trợ kiểm thử Selenium ở chế độ headless và full-browser, đảm bảo khả năng tương thích trên nhiều môi trường.
- Tích hợp liền mạch với CI/CD: Hoạt động tốt với Bitbucket Pipelines, GitHub Actions, và GitLab CI/CD.
- Ghi lại video quá trình kiểm thử: Với .withRecording(), mọi phiên kiểm thử trình duyệt đều có thể được ghi lại để giúp debug trực quan hơn.
- Phản hồi nhanh hơn với Wait Strategies: Đảm bảo container đã khởi tạo hoàn chỉnh trước khi bắt đầu kiểm thử, giúp tránh các lỗi race condition.
- Môi trường kiểm thử tùy chỉnh: QA teams có thể định nghĩa container riêng bằng GenericContainer hoặc tạo hình ảnh Docker tùy chỉnh.
Với Testcontainers, QA teams có thể chạy kiểm thử chính xác hơn, đáng tin cậy hơn, và hiệu quả hơn, mô phỏng điều kiện sản xuất một cách sát thực nhất.
Các loại Container được hỗ trợ
- Cơ sở dữ liệu: PostgreSQL, MySQL, MongoDB, Redis, v.v.
- Message brokers: Kafka, RabbitMQ
- Trình duyệt Selenium: Chạy kiểm thử giao diện ở chế độ headless hoặc full-browser
- Container tùy chỉnh: Tạo image và cấu hình theo nhu cầu
Wait Strategies – Chiến lược chờ
Testcontainers cung cấp nhiều chiến lược chờ (Wait Strategies) để đảm bảo container đã sẵn sàng trước khi kiểm thử tương tác với nó. Điều này giúp tránh lỗi race condition, khi kiểm thử có thể cố gắng truy cập vào container trước khi nó hoàn tất khởi tạo.
Một số Wait Strategies phổ biến:
- Wait.forLogMessage(regex, times) – Chờ một log message cụ thể xuất hiện số lần nhất định.
- Wait.forHealthCheck() – Chờ cho đến khi container trả về trạng thái "healthy".
- Wait.forListeningPorts(port) – Đảm bảo một cổng cụ thể trong container đã mở trước khi tiếp tục.
- Wait.forHttp(path, statusCode) – Chờ một HTTP endpoint phản hồi với mã trạng thái cụ thể.
Với Testcontainers, việc kiểm thử tích hợp trở nên dễ dàng hơn, chính xác hơn và gần với môi trường thực tế hơn.
Ví dụ về việc sử dụng chiến lược chờ trong Testcontainers cho vùng chứa PostgreSQL:
import { GenericContainer, Wait } from "testcontainers";
const container = await new GenericContainer("postgres:latest")
.withExposedPorts(5432)
.withEnv("POSTGRES_USER", "testuser")
.withEnv("POSTGRES_PASSWORD", "testpassword")
.withWaitStrategy(Wait.forLogMessage("database system is ready to accept connections", 2))
.start();
Sử dụng chiến lược chờ đảm bảo rằng container được khởi tạo hoàn toàn trước khi bộ kiểm thử bắt đầu thực thi, giúp giảm sự không ổn định trong các bài kiểm thử.
Xây dựng hình ảnh của riêng bạn
Ngoài việc sử dụng hình ảnh container dựng sẵn, Testcontainers cho phép bạn xây dựng và sử dụng hình ảnh container tùy chỉnh phù hợp với nhu cầu thử nghiệm của bạn. Bạn có thể tạo hình ảnh tùy chỉnh bằng cách sử dụng GenericContainer
và chỉ định Dockerfile hoặc hình ảnh hiện có:
import { GenericContainer } from "testcontainers";
const container = await new GenericContainer("node:latest")
.withCopyFileToContainer("./my-app", "/usr/src/app")
.withExposedPorts(3000)
.withCommand(["npm", "start"])
.start();
console.log(`Server running at http://localhost:${container.getMappedPort(3000)}`);
Cách tiếp cận này hữu ích khi thử nghiệm các ứng dụng yêu cầu các phụ thuộc tùy chỉnh hoặc cấu hình cụ thể. Bạn cũng có thể xây dựng một hình ảnh từ Dockerfile một cách động bằng cách sử dụng withBuild:
const container = await GenericContainer.fromDockerfile("./path/to/Dockerfile").build();
Sử dụng Testcontainers trong TypeScript
Dưới đây là một ví dụ về việc sử dụng Testcontainer với Selenium trong dự án TypeScript để chạy thử nghiệm UI trong quy trình CI/CD (ví dụ: Bitbucket).
Điều kiện tiên quyết:
- Docker được cài đặt trên máy hoặc môi trường CI của bạn.
- Đã cài đặt Node.js và TypeScript.
- Các phụ thuộc của Selenium WebDriver (selenium-webdriver, @testcontainers/selenium, dotenv, v.v.).
Thiết lập Testcontainer cho Selenium:
import * as dotenv from 'dotenv';
import { After, AfterAll, Before, BeforeAll, setDefaultTimeout, Status } from '@cucumber/cucumber';
import { Browser, Builder } from 'selenium-webdriver';
import * as chrome from 'selenium-webdriver/chrome';
import { SeleniumContainer } from '@testcontainers/selenium';
setDefaultTimeout(300000);
export let browser: any;
let container: any;
BeforeAll(async () => {
dotenv.config();
container = await new SeleniumContainer('seleniarm/standalone-chromium:latest')
.withRecording() // Enables video recording of the test execution
.start();
});
Before(async () => {
const chromeOptions = new chrome.Options()
.addArguments('--start-maximized')
.addArguments('--disable-notifications')
.addArguments('--no-sandbox')
.addArguments('--headless');
browser = await new Builder()
.forBrowser(Browser.CHROME)
.setChromeOptions(chromeOptions)
.usingServer(container.getServerUrl())
.build();
await browser.manage().setTimeouts({ implicit: 30000, pageLoad: 120000, script: 30000 });
await browser.get('https://example.com/login');
await browser.manage().deleteAllCookies();
});
After(async function (testCase) {
if (testCase.result?.status === Status.FAILED) {
const image = await browser.takeScreenshot();
this.attach(image, 'base64:image/png');
}
await browser.quit();
});
AfterAll(async () => {
const stoppedContainer = await container.stop();
await stoppedContainer.saveRecording('./image/lastExecution.mp4'); // Saves the execution video
});
Chạy Testcontainer trong CI/CD Pipeline
Testcontainers tích hợp liền mạch vào Bitbucket Pipelines (hoặc các môi trường CI/CD khác) để đảm bảo thực hiện thử nghiệm nhất quán trên các môi trường khác nhau. Dưới đây là cấu hình bitbucket-pipelines.yml mẫu để chạy thử nghiệm Selenium:
image: node:latest
pipelines:
default:
- step:
name: Run Selenium Tests with Testcontainers
services:
- docker
script:
- npm install
- npm test
Thiết lập này đảm bảo rằng các bài kiểm tra của bạn chạy bên trong đường ống hỗ trợ Docker, tận dụng Testcontainer để thực hiện bài kiểm tra đáng tin cậy và riêng biệt.
Phần kết luận
Testcontainers là một công cụ mạnh mẽ giúp đơn giản hóa việc kiểm thử tích hợp bằng cách cung cấp các môi trường thực tế, dùng một lần. Cho dù bạn đang kiểm thử cơ sở dữ liệu, hàng đợi tin nhắn hay các bài kiểm thử UI dựa trên Selenium, nó đảm bảo rằng các bài kiểm thử đáng tin cậy và nhất quán trên các môi trường khác nhau. Ngoài ra, các bản ghi video về quá trình thực hiện kiểm thử cho phép gỡ lỗi và xác minh dễ dàng, khiến nó trở thành một công cụ có giá trị cho cả quá trình phát triển cục bộ và quy trình CI/CD.
Để linh hoạt hơn nữa, hãy xây dựng hình ảnh của riêng bạn với GenericContainer
hoặc fromDockerfile
cho phép môi trường thử nghiệm tùy chỉnh phù hợp với nhu cầu của ứng dụng. Sử dụng Wait Strategies đảm bảo rằng các container được khởi tạo đầy đủ trước khi thực thi, giảm độ không ổn định và cải thiện tính ổn định của thử nghiệm.
Cảm ơn các bạn đã theo dõi!
All rights reserved