📖 Guide DocumentsE2E TestingWhy E2E Test?

Outline

E2E test functions rather than unit test functions.

When developing a test program for NestJS developed backend server, I recommend to adapt E2E test paradigm instead of unit test paradigm. It’s because with the @nestia/sdk generated SDK library, E2E test functions can be much easier, safer and efficient for production than the traditional unit test functions.

Furthermore, if you develop test functions utilizing the SDK library, you can easily switch the e2e test functions to the performance benchmark functions. Just by utilizing @nestia/e2e and @nestia/benchmark libraries, you can easily measure your NestJS developed backend server’s performance through the SDK library utilizing e2e test functions.

SDK

SDK library utilizing test functions can be used in the performance benchmark program

Efficient for Production

New era, age of E2E testing paradigm comes.

In the past era, backend developers had developed test programs following the unit test paradigm. It’s because traditional E2E test functions’ development could not take any advantage of compiled language’s type safety. As you can see from the below example code, E2E test functions had to write hard-coded fetch() function with string literals.

Besides, unit test could take advantages of compiled language’s type safety by importing related modules. Therefore, it was more efficient to develop test functions following the unit test paradigm. This is the reason why unit test paradigm had been loved in the past era.

import { TestValidator } from "@nestia/e2e";
import typia from "typia";
 
import { IBbsArticle } from "@samchon/bbs-api/lib/structures/bbs/IBbsArticle";
 
export const test_api_bbs_article_create = async (
  host: string,
): Promise<void> => {
  // In the traditional age, E2E test function could not take advantages 
  // of type safety of the TypeScript. Instead, have to write hard-coded
  // `fetch()` function with string literals.
  const response: Response = await fetch(`${host}/bbs/articles`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      writer: "someone",
      password: "1234",
      title: "title",
      body: "content",
      format: "md",
      files: [],
    } satisfies IBbsArticle.ICreate),
  });
  const article: IBbsArticle = await response.json();
  typia.assert(article);
 
  const read: IBbsArticle = await (async () => {
    const response: Response = await fetch(`${host}/bbs/articles/${article.id}`);
    const article: IBbsArticle = await response.json();
    return typia.assert(article);
  })();
  TestValidator.equals("written")(article)(read);
};

However, in the new era, e2e test functions also can take advantages of the type safety. Just import SDK library generated by @nestia/e2e, and call API functions of it with TypeScript type hints. In this way, as both e2e test paradigm and unit test paradigm can take advantages of type safety, we have to consider which strategy is suitable for the production environment.

In here article, I recommend to adapt e2e test paradigm in the below reasons.

  • suitable for CDD (Contract Driven Development)
  • easy to develop and maintain
  • much safer than unit testing due to its coverage
  • can be used for the performance benchmark
  • can guide client developers as an example code

Look at the below example code of new era’s e2e test function, and compare it with the traditional unit test function. As you can see, e2e test function actually tests the backend server’s behavior by calling the real API endpoints of it. Besides, unit test can’t test the backend server’s actual behavior. It just validates the provider’s behavior. This is the reason why new era’s e2e test function is safer than unit test function.

Also, such new era’s e2e test function can be provided to the client or frontend developers as an example code. It guides them how to call the backend server’s API endpoints through the SDK library. In this way, e2e test function can be used as a well-structured document for the client developers.

import { TestValidator } from "@nestia/e2e";
import typia from "typia";
 
import BbsApi from "@samchon/bbs-api";
import { IBbsArticle } from "@samchon/bbs-api/lib/structures/bbs/IBbsArticle";
 
export const test_provider_bbs_article_create = async (
  connection: BbsApi.IConnection
): Promise<void> => {
  // Unit test functions can't validate 
  // the backend server's actual behavior.
  const article: IBbsArticle = await BbsApi.functional.bbs.articles.create(
    connection,
    {
      writer: "someone",
      password: "1234",
      title: "title",
      body: "content",
      format: "md",
      files: [],
    },
  );
  typia.assert(article);
 
  // This is the reason why I've adopted the e2e test paradigm
  const read: IBbsArticle = await BbsApi.functional.bbs.articles.at(
    connection,
    article.id,
  );
  typia.assert(read);
  TestValidator.equals("written")(article)(read);
};

At last, the new era’s e2e test functions can be used for the performance benchmark without any extra dedication. As the e2e test function directly calls the API endpoints of the backend server, backend server performance benchmark program can be easily developed by utilizing them.

Those are the reasons why I recommend to adapt the new era’s e2e test paradigm instead of the traditional unit test paradigm. Those are the reason why I am insisting that e2e test functions are efficient for production. From now on, let’s see how to compose the e2e test functions for the NestJS developed backend server.

You can experience benchmark program utilizing e2e test functions.

💻 https://stackblitz.com/~/github.com/samchon/nestia-start

Benchmark Result Screenshot

Test Program Development

test/features/api/bbs/test_api_bbs_article_create.ts
import { RandomGenerator, TestValidator } from "@nestia/e2e";
import { v4 } from "uuid";
 
import api from "@ORGANIZATION/PROJECT-api/lib/index";
import { IBbsArticle } from "@ORGANIZATION/PROJECT-api/lib/structures/bbs/IBbsArticle";
 
export async function test_api_bbs_article_create(
  connection: api.IConnection,
): Promise<void> {
  // STORE A NEW ARTICLE
  const stored: IBbsArticle = await api.functional.bbs.articles.create(
    connection,
    "general",
    {
      writer: RandomGenerator.name(),
      title: RandomGenerator.paragraph(3)(),
      body: RandomGenerator.content(8)()(),
      format: "txt",
      files: [
        {
          name: "logo",
          extension: "png",
          url: "https://somewhere.com/logo.png",
        },
      ],
      password: v4(),
    },
  );
 
  // READ THE DATA AGAIN
  const read: IBbsArticle = await api.functional.bbs.articles.at(
    connection,
    stored.section,
    stored.id,
  );
  TestValidator.equals("created")(stored)(read);
}

Just make test functions utillizing SDK library, and export those functions with test_ prefixed names. And then if compose the main program of the test, all of the test functions would be automatically mounted and executed whenever you run the main test program.

If you want to experience the test program earlier, visit below playground website.

💻 https://stackblitz.com/~/github.com/samchon/nestia-start

- test_api_bbs_article_at: 149 ms
- test_api_bbs_article_create: 30 ms
- test_api_bbs_article_index_search: 1,312 ms
- test_api_bbs_article_index_sort: 1,110 ms
- test_api_bbs_article_update: 28 m

Performance Benchmark

test/benchmark/servant.ts
import { DynamicBenchmarker } from "@nestia/benchmark";
 
import { MyConfiguration } from "../../src/MyConfiguration";
 
DynamicBenchmarker.servant({
  connection: {
    host: `http://127.0.0.1:${MyConfiguration.API_PORT()}`,
  },
  location: `${__dirname}/../features`,
  parameters: (connection) => [connection],
  prefix: "test_api_",
}).catch((exp) => {
  console.error(exp);
  process.exit(-1);
});

You can re-use test functions for the performance benchmark program.

Just compose the benchmark’s main and servant programs like above pointing the test functions’ directory, then the benchmark program would utilize those test functions for the backend server performance measurement. The benchmark program will make multiple worker threads, and let them to make requests to the backend server simultaneously through the test functions.

If you want to experience the benchmark program earlier, visit below playground website.

💻 https://stackblitz.com/~/github.com/samchon/nestia-start

? Number of requests to make 1024
? Number of threads to use 4
? Number of simultaneous requests to make 32
████████████████████████████████████████ 100% | ETA: 0s | 3654/1024

Benchmark Image

Last updated on