最近有很多朋友来找我聊测试相关的内容,发现他们对测试的分类有点迷茫。其实测试分为三种:E2E,集成,单体测试,其他功能测试,UI测试,界面测试只是其中一种。KentC.Dodds[1]在这篇文章《Static vs Unit vs Integration vs E2E Testing for Frontend Apps》[2]中也谈到了这三个测试的比较和区别。同学帮忙。所以今天把这篇文章分享给大家~我会尽量在翻译中使用更地道的语言,也就是在原文的基础上加一层Buf。如果您想阅读原文,请点击此处[3]。J.B.Rainsberger在我的采访中说了一个我非常喜欢的比喻:你可以把油漆扔到墙上,你可能会涂满大部分的墙,但除非你用刷子刷墙,否则你永远不会刷到角落。我喜欢用它来类比测试,因为做测试就像画一堵墙,你必须在开始之前选择正确的策略。你用小刷头刷墙吗?当然不是。那将需要很长时间,而且效果会参差不齐。你用滚筒来画一切吗?就像你曾曾祖母从200年前从某处带来的豪华家具?绝对不。不同的刷子适用于不同的情况,测试也是如此。这就是我构建这个测试模型[4]的原因。在这个模型中,有4个测试类别:端到端测试:使用行为像用户的机器人与App进行交互并验证功能是否正常。有时也称为“功能测试”或E2E。集成测试:验证多个单元是否协同工作。单元测试:验证单独的隔离部分是否正常工作。静态测试:在编写代码时发现拼写错误和类型错误。在这个模型中,每个测试类别的大小与你在测试时付出的注意力呈正相关(通常)。让我深入谈谈差异、含义以及如何优化这些类型的测试。测试类型让我们从上到下看几个这几种测试的例子:用户。以下示例是使用Cypresss实现的:=generate.user()consttodo=generate.todo()//在这里我们将遍历整个注册过程//我通常只写一个测试来做这个//其余的测试将直接通过HTTP请求发送实现注册功能//这样我们就可以跳过注册表单的交互过程cy.visitApp()cy.findByText(/register/i).click()cy.findByLabelText(/username/i).type(user.username)cy.findByLabelText(/password/i).type(user.password)cy.findByText(/login/i).click()cy.findByLabelText(/addtodo/i).type(todo.description)。类型('{enter}')cy.findByTestId('todo-0').should('have.value',todo.description)cy.findByLabelText('complete').click()cy.findByTestId('todo-0').should('have.class','complete')//等等...//我的E2E测试通常像真实用户一样编写//sometimesverylong})})集成测试集成测试背后的想法是尽可能少的模拟。我通常只mock以下两点:网络请求(使用MSW[5])实现动画组件(因为谁想在测试中等待)下面的测试用例将渲染整个应用程序。但这并不是集成测试的硬性要求,而且我编写的大多数集成测试都不会渲染整个应用程序。它们通常只渲染要在App中使用的Provider(这是render在test/app-test-utils伪模块中所做的):import*asReactfrom'react'import{render,screen,waitForElementToBeRemoved}from'测试/app-test-utils'从'@testing-library/user-event'导入用户事件从'@jackfranklin/test-data-bot'导入{rest}从'@jackfranklin/test-data-bot'导入{setupServer}从'msw/node'import{handlers}from'test/server-handlers'importAppfrom'../app'constbuildLoginForm=build({fields:{username:fake(f=>f.internet.userName()),password:fake(f=>f.internet.password()),},})//集成测试一般只使用MSW库来MockHTTP请求constserver=setupServer(...handlers)beforeAll(()=>server.listen())afterAll(()=>server.close())afterEach(()=>server.resetHandlers())test(`登录显示用户名`,async()=>{//这个自定义渲染会在App加载时返回一个Promise//(如果你使用服务器渲染,你可能不会tneedtodothis)//这个自定义渲染还允许你指定你的初始路由awaitrender(
