文章由 UI 测试最佳实践项目 内容翻译而来,大家有条件的话可以去 UI 测试最佳实践项目阅读原文。

真实案例:用集成测试测试前端,用 E2E 测试测试后端

原文链接:https://github.com/NoriSte/ui-testing-best-practices/blob/master/sections/real-life-examples/test-front-end-with-integration-back-end-with-e2e.md

一段简要说明

使用带有存根服务器的 UI 测试相对于完整的 E2E 测试来说,不仅更加可靠,而且速度更快

尽管完整的 E2E 测试仍然提供了最高的信心水平,但代价很高:易碎、潜在不可靠且速度较慢。

通过使用成本较低的 UI 集成测试,我们仍然可以在前端获得高信心水平,并将成本较高的 E2E 测试留给后端。

示例测试架构图

这是来自实际的建筑控制云应用程序的高层次架构视图。

  • Angular 前端
  • Node-Express API(后端)
  • 服务(Go lambdas)(后端)
  • 硬件(后端)

根据需求,可以通过纯 API 测试来补充 UI-E2E 测试。一些常用的 API 测试工具包括 PostmanVS Code 的 Rest Client,以及 Cypress。

请注意:以下所有示例均使用 Cypress,目前它在 XHR 测试支持方面是最优秀的。在现有的测试工具中,完整的 XHR 请求等待和检查并不常见,Cypress 目前提供了最全面的检查支持。

代码示例:登录测试

以下示例包含两个测试,用于覆盖登录功能。第一个测试使用 UI 集成测试覆盖前端应用程序,第二个测试使用 E2E 测试覆盖后端。

/** function to fill username, password and Login*/
const fillFormAndClick = ({ username, password }) => { .. };

// This is an UI integration test with server stubbing.
// Remember to write a few E2E tests and a lot of integration ones
// @see https://github.com/NoriSte/ui-testing-best-practices/blob/master/sections/testing-strategy/component-vs-integration-vs-e2e-testing.zh.md#ui-integration-tests
it("Login: front-end integration tests", () => {

  // A route that intercepts / sniffs every POST request that goes to the authentication URL.
  // Stubs the response with authentication-success.json fixture. This is called server stubbing
  cy.intercept({
    method: "POST",
    fixture: "authentication/authentication-success.json", // Stubs the response
    url: `**${AUTHENTICATE_API_URL}`
  }).as("auth-xhr");

  fillFormAndClick(USERNAME_PLACEHOLDER, PASSWORD_PLACEHOLDER);

  // wait for the POST XHR
  cy.wait("@auth-xhr").then(interception => {
    // assert the payload body that the front end is sending to the back-end
    expect(interception.request.body).to.have.property("username", username);
    expect(interception.request.body).to.have.property("password", password);
    // assert the request headers in the payload
    expect(interception.request.headers).to.have.property('Content-Type', 'application/json;charset=utf-8');
  });

  // finally, the user must see the feedback
  cy.getByText(SUCCESS_FEEDBACK).should("be.visible");
});

// this is a copy of the integration test but without server stubbing.
it("Login: back-end E2E tests", () => {

  // A route that intercepts / sniffs every POST request that goes to the authentication URL.
  // Distinction: this is NOT stubbed!
  cy.intercept({
    method: "POST",
    url: `**${AUTHENTICATE_API_URL}`
  }).as("auth-xhr");

  fillFormAndClick(USERNAME_PLACEHOLDER, PASSWORD_PLACEHOLDER);

  cy.wait("@auth-xhr").then(interception => {
    // since the integration tests already tested the front-end app, we use E2E tests to check the
    // back-end app. It needs to ensure that the back-end app works and gets the correct response data

    // response body assertions and status should be in the E2E tests since they rely on the server
    expect(interception.status).to.equal(200);
    expect(interception.response.body).to.have.property("token");
  });

  // finally, the user must see the feedback
  cy.getByText(SUCCESS_FEEDBACK).should("be.visible");
});

代码示例 2:将 UI 集成测试切换为 UI-E2E 测试

有时候,您可能希望将 UI 集成测试切换为 E2E 测试。

在较低级别的测试层面,例如仅将测试隔离到 UI 代码时,您可能更愿意使用经济高效的 UI 集成测试。

而在较高级别的测试层面,例如与中间层服务集成时,您可能需要更高的信心水平,将测试目标定位到后端。

通过使用条件存根,您可以在 UI 集成测试和 E2E 测试之间切换关注。

// stub-services.js : a file that only includes a function to stub the back-end services
export default function() {
  // all routes to the specified endpoint will respond with pre-packaged Json data
  cy.intercept('/api/../me', {fixture:'services/me.json'});
  cy.intercept('/api/../permissions', {fixture:'services/permissions.json'});
  // Lots of other fixtures ...
}

// spec file:
import stubServices from '../../support/stub-services';

/** isLocalhost is a function that checks the configuration environment*/
const isLocalHost = () => Cypress.env('ENVIRONMENT') === "localhost";

// ... in your tests, or in before / beforeEach blocks,
// stub the services if you are testing front-end (UI integration tests)
// do not stub if you are testing the back-end (UI-E2E tests)
if (isLocalHost()) {
  stubServices();
}

参考资料


欢迎关注软件测试同学的公众号“软件测试同学”,原创 QA 技术文章第一时间推送。