【问题标题】:Combine individual tests into single end-to-end test without repeating code将单个测试组合成单个端到端测试,无需重复代码
【发布时间】:2019-02-14 21:27:56
【问题描述】:

我们编写了一组赛普拉斯测试来检查我们应用程序每个部分的特定功能:customer_spec.js、order_spec.js、delivery_spec.js、doJob_spec.js 等。这似乎遵循了推荐的最佳实践赛普拉斯,孤立地测试每一件事。我们希望能够在一个文件中调用这些单独的测试 - 或测试的一部分 - 以构建端到端测试,同时仍然保持运行单独测试的能力。这个概念在一定程度上存在于 command.js 文件中创建的命令(例如 login)中,然后您可以在个人测试中调用这些命令(使用 login()),而不是重复登录代码。

我们找不到任何文档说明这是否可行以及如果可行,该怎么做。我们的想法是能够创建一个 customer_life_cycle_spec.js 文件,然后调用 login()、addcustomer()、dojob()、orderitems()、receiveitems() 等。

【问题讨论】:

  • 我不请自来的建议:我猜有人(你的经理?)告诉你需要这种类型的工作流测试,即使你已经测试了每个单独的操作,它提供了相同的覆盖率和信心.我建议您让他们了解为什么赛普拉斯建议以这种方式进行测试,而不是编写重复的测试来取悦他们。
  • 这是一个开发讨论导致的。孤立地测试事物是一种很好的做法,但与大多数应用程序一样,此应用程序中存在相互依赖关系,即隔离不会测试。我们的端到端测试旨在确认对一个实体的更改会影响另一个实体。我们有一个我们正在尝试重新创建的工作流程,这是对创建实体、使用它们、验证、然后撤消和清理实体的真实测试。孤立地测试事物不允许我们创建真实世界的测试,这是赛普拉斯的另一个目标。撇开哲学问题不谈,只是确定技术的可行性。
  • 我相信您可以在隔离测试中设置状态,这样就不会通过长时间运行的端到端测试来测试任何额外的东西,但我们同意不同意这一点。如果您打算这样做,我会使用自定义命令,例如“createEntity”、“readEntity”、“updateEntity”、“deleteEntity”(或任何根据您的应用程序有意义的名称)。然后从两个测试中调用它们。较小的测试将通过 API 设置、验证和拆除状态,所有 UI 操作都将通过这些自定义命令完成
  • 您可以通过将外部describe 包装在一个函数中来模块化测试套件,然后从另一个测试中导入和调用该函数。但是,我不确定如何在 Cypress 运行器中单独(自动)运行打包的测试套件。

标签: cypress


【解决方案1】:

是的,Cypress 支持在您的 UI 中创建和重用操作和状态的功能,例如在测试前注册和登录。

然而Cypress,通过cy.request() 允许您比用户更强大地控制浏览器的状态,使您的测试更简单更快更可靠

查看下面的示例,其中cy.request 用于在您的服务器上创建/读取状态。

commands/index.js:

Cypress.Commands.add('login', (user) => {
    cy.request('POST', `${apiUrl}/users/login`, user)
})

Cypress.Commands.add("register", (user) => {
    cy.request('POST', `${apiUrl}/users/register`, user)
})

Cypress.Commands.add('getUser', (username) => {
    return cy.request('GET', `${apiUrl}/users/${username}`)
})

register.spec.js:

it ('can register', () => {
    const user = {
      name: 'jake',
      email: 'jake@jake.com',
      password: '12345'
    }

    cy.visit('/register')
    cy.get('input[name="name"]').type(user.name)
    cy.get('input[name="email"]').type(user.email)
    cy.get('input[name="password"]').type(user.password)
    cy.get('input[name="password-confirm"]').type(user.password)
    cy.get('input[type="submit"]').click()

    // ensure register page sends you /home after register
    cy.url().should('contain', '/home')

    // expect user from server to match user from test
    cy.getUser(user.name)
    .then((dbUser) => expect(dbUser).to.deep.eql(user))
})

login.spec.js:

it('can log in', () => {
    const user = {
        name: 'jane',
        email: 'jane@jane.com',
        password: '12345'
    }

    // register w/out UI
    cy.register(user)

    cy.visit('/login')
    cy.get('input[name="name"]').type(user.name)
    cy.get('input[name="password"]').type(user.password)
    cy.get('input[type="submit"]').click()

    // ensure the login page sends you home after login
    cy.url().should('contain', '/home')
})

userSettings.spec.js:

it('can change email', () => {
    const user = {
        name: 'jane',
        email: 'jane@jane.com',
        password: '12345'
    }

    // register and login w/o UI
    cy.register(user)
    cy.login(user)

    cy.visit('/settings')
    cy.get('input[name="email"]').type('UpdatedEmail@jane.com')
    cy.get('input[type="submit"]').click()

    cy.getUser(user.name)
    .then((dbUser) => expect(dbUser.email).to.eql('UpdatedEmail@jane.com'))
})

【讨论】:

    猜你喜欢
    • 2014-03-20
    • 1970-01-01
    • 2016-06-07
    • 1970-01-01
    • 1970-01-01
    • 2013-12-07
    • 2017-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多