这篇文章值得您关注,如果您 热衷于编写高质量的软件,并希望通过测试来增强应用程序的稳定性。 厌倦了生产系统中突然出现的意外错误。 需要帮助了解什么是自动化测试以及如何进行它们。 为什么我们需要自动化测试? 作为工程师,我们希望构建 ,但随着我们创建的每一个新功能,我们不可避免地会增加应用程序的大小和复杂性。 有用的 东西 随着产品的发展, (例如用手)测试受更改影响的每个功能变得越来越耗时。 手动 缺乏自动化测试导致我们要么花费太多时间并降低运输速度,要么花费太少来节省速度,从而导致积压中出现新的错误以及来自 PagerDuty 的深夜电话。 相反, 。那么, 计算机可以通过编程重复执行相同的操作 让我们将测试委托给计算机吧! 测试类型 提出了 。让我们深入研究每种类型并了解为什么我们需要每种类型。 测试金字塔思想 三种主要类型的测试:单元测试、集成测试和端到端测试 单元测试 是您 测试的一小段逻辑(不依赖其他组件)。 单元 单独 他们在几秒钟内完成。 允许他们在任何时间点、本地和 CI 上运行它们,而无需启动依赖的服务/进行 API 和数据库调用。 单元测试很快。 隔离 接受两个数字并将它们相加的函数。我们想用不同的参数调用它并断言返回的值是正确的。 单元测试示例: // Function "sum" is the unit const sum = (x, y) => x + y test('sums numbers', () => { // Call the function, record the result const result = sum(1, 2); // Assert the result expect(result).toBe(3) }) test('sums numbers', () => { // Call the function, record the result const result = sum(5, 10); // Assert the result expect(result).toBe(15) }) 一个更有趣的例子是 React 组件,它在 API 请求完成后呈现一些文本。我们需要模拟 API 模块以返回测试所需的值、渲染组件并断言渲染的 HTML 具有我们需要的内容。 // "MyComponent" is the unit const MyComponent = () => { const { isLoading } = apiModule.useSomeApiCall(); return isLoading ? <div>Loading...</div> : <div>Hello world</div> } test('renders loading spinner when loading', () => { // Mocking the API module, so that it returns the value we need jest.mock(apiModule).mockReturnValue(() => ({ useSomeApiCall: jest.fn(() => ({ // Return "isLoading: false" for this test case isLoading: false })) })) // Execute the unit (render the component) const result = render(<MyComponent />) // Assert the result result.findByText('Loading...').toBeInTheDocument() }) test('renders text content when not loading', () => { // Mocking the API module jest.mock(apiModule).mockReturnValue(() => ({ useSomeApiCall: jest.fn(() => ({ // Return "isLoading: false" for this test case isLoading: false })) })) // Execute the unit (render the component) const result = render(<MyComponent />) // Assert the result result.findByText('Hello world').toBeInTheDocument() }) 集成测试 当您的 与其他 交互时,我们将其称为 。这些测试比单元测试慢,但它们测试应用程序各部分的连接方式。 单元 单元(依赖项) 集成 在数据库中创建用户的服务。这要求执行测试时数据库实例( )可用。我们将测试该服务是否可以从数据库创建和检索用户。 集成测试示例: 依赖项 import db from 'db' // We will be testing "createUser" and "getUser" const createUser = name => db.createUser(name) // creates a user const getUser = name => db.getUserOrNull(name) // retrieves a user or null test("creates and retrieves users", () => { // Try to get a user that doesn't exist, assert Null is returned const nonExistingUser = getUser("i don't exist") expect(nonExistingUser).toBe(null); // Create a user const userName = "test-user" createUser(userName); // Get the user that was just created, assert it's not Null const user = getUser(userName); expect(user).to.not.be(null) }) 端到端测试 当我们测试 时,这是一个 测试,其中所有依赖项都可用。这些测试最好地模拟实际用户行为,并允许您捕获应用程序中 ,但它们是 测试类型。 完全部署的应用程序 端到端 所有可能的问题 最慢的 每当您想要运行端到端测试时,您都必须配置所有基础设施并确保第三方提供商在您的环境中可用。 您 将它们用于应用程序的 功能。 只想 关键任务 登录流程。我们想要转到应用程序,填写登录详细信息,提交,然后查看欢迎消息。 让我们看一个端到端的测试示例: test('user can log in', () => { // Visit the login page page.goto('https://example.com/login'); // Fill in the login form page.fill('#username', 'john'); page.fill('#password', 'some-password'); // Click the login button page.click('#login-button'); // Assert the welcome message is visible page.assertTextVisible('Welcome, John!') }) 您如何选择要编写哪种类型的测试? 请记住, , 。 端到端测试比集成慢 集成测试比单元测试慢 如果您正在开发的功能是关键任务,请考虑至少编写一个 测试(例如在开发身份验证流程时检查登录功能如何工作)。 端到端 除了关键任务流程之外,我们还希望测试尽可能多的边缘情况和功能的各种状态。 使我们能够测试应用程序的各个部分如何协同工作。 集成测试 端点应该执行操作,产生预期的结果,并且不会抛出任何意外的错误。 对端点和客户端组件进行集成测试是一个好主意。 客户端组件应该显示正确的内容并按照您期望的方式响应用户交互。 最后,我们什么时候应该选择 ?所有可以单独测试的小函数,例如对数字求和的 、呈现 标记的 ,都是单元测试的绝佳候选者。如果您遵循 方法,那么单元就是完美的。 单元测试 sum <button> Button 测试驱动开发 下一步是什么? (但从小处开始) 写一些测试! 。每种语言都有一个流行的测试库,例如用于 JavaScript 的 / 、用于端到端的 / (也使用 JavaScript)、用于 Java 的 等。 安装适合您的项目/语言的测试框架 Jest Vitest Cypress Playwright JUnit 在项目中找到一个小函数并为其编写 测试。 单元 为某些组件/服务-数据库 测试。 交互编写集成 选择一个可以快速测试的关键场景,例如简单的登录流程,并为其编写 测试。 端到端 执行上述操作一次即可了解其工作原理。然后,在某些功能/错误工作期间再次执行此操作。然后分享给你的同事,让大家都写测试,节省时间,晚上睡得更好! 有用的资源: 我的 个人博客 的 Ham Vocke 实用测试金字塔 作者: 测试驱动开发, Martin Fowler