14
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Jestを使ったテスト高速化のため、ts-jestではなく、@swc/jestを使ってみたら予想以上に速かった話

Posted at

はじめに

TypeScriptでJestを使ってテストをする時、テストの実行速度が遅いことに不満を感じていました。

なんとなくTypeScript→JavaScriptへのビルドに時間がかかっているのだろうなと想像はついていたので、最近は es-build とかもあるため、テストの実行速度を上げることはできるのではないか?と考えました。

テストの実行速度を上げる方法を調べてみる

ありました。

TypeScript→JavaScriptへのビルドにts-jestを使うのではなく、 esbuild-jest を使う方法です。

ですが、 esbuild-jest はPRの多くがマージされずに開発が途中で停止している様子です。(2022/09 時点)

これは困ったな。。。と、他の方法はないか調べてみると。。。。ありました。

今度は、ts-jestを使うのではなく、 @swc/jest を使う方法です。

SWCは、Speedy Web Compilerの略で、Rustで作られた次世代のコンパイラだそうです。

swc-projectがあり、その1つに jest が含まれている感じですね。

SWCは実績もあり、Next.js、Parcel、Deno などのツールや、Vercel、ByteDance、Tencent、Shopify などの企業で使用されているとのこと。

これは期待できる。。。ということで、早速使ってみることにしました。

@swc/jest をインストール、Configファイルを用意する

とりあえずインストール。

yarn add -dev jest @types/jest @swc/core @swc/jest

jest.config.json では、向き先を ts-jest ではなく、 @swc/jest に。。。

  • jest.config.json
{
  "transform": {
    "^.+\\.(t|j)sx?$": ["@swc/jest"]
  },
  "testEnvironment": "node"
}

@swc/jest は、別途 .swcrc というConfigファイルを作ります。

  • .swcrc
{
  "$schema": "https://json.schemastore.org/swcrc",
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "dynamicImport": false,
      "decorators": false
    },
    "target": "es2022",
    "loose": false,
    "externalHelpers": false
  },
  "minify": false
}

各々の設定内容は以下に記載してあります。

.swcrc を作って、 target を指定していることから、 tsconfig.json の内容は見ていないのでしょうね。

tsconfig.json を見ていないことで、何か大きな問題があるかというと。。。。微妙な気がします。

大抵は困らない気がする。。。

さておき、動かしてみましょう。

テストする

  • AWS S3のBucketからファイルを取得するコードのサンプル。
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';

export async function main() {
  try {
    const s3 = new S3Client({ region: 'ap-northeast-1' });
    const obj = await s3.send(
      new GetObjectCommand({
        Bucket: 'dummyBucket',
        Key: 'dummyKey',
      })
    );
    if (
      obj.$metadata.httpStatusCode !== undefined &&
      obj.$metadata.httpStatusCode >= 400
    ) {
      return 'NG';
    }
    return 'OK';
  } catch (error) {
    return error as Error;
  }
}
  • 上記コードのサンプルのテストコード。
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { mockClient } from 'aws-sdk-client-mock';
import * as fs from 'fs';
import * as path from 'path';
import { main } from './main';

// main.tsのテスト
const s3Mock = mockClient(S3Client);
beforeEach(() => {
  s3Mock.reset();
});

describe('S3のオブジェクトを取得できる', () => {
  it('成功', async () => {
    s3Mock
      .on(GetObjectCommand, {
        Bucket: 'dummyBucket',
        Key: 'dummyKey',
      })
      .resolves({
        $metadata: {
          httpStatusCode: 200,
        },
        Body: fs.createReadStream(
          path.resolve(__dirname, './main.test.s3read.txt')
        ),
      });

    expect(await main()).toBe('OK');
  });

  it('失敗', async () => {
    s3Mock
      .on(GetObjectCommand, {
        Bucket: 'dummyBucket',
        Key: 'dummyKey',
      })
      .resolves({
        $metadata: {
          httpStatusCode: 400,
        },
        Body: fs.createReadStream(
          path.resolve(__dirname, './main.test.s3read.txt')
        ),
      });

    expect(await main()).toBe('NG');
  });
});

describe('S3のオブジェクトを取得できない', () => {
  it('成功', async () => {
    const error = new Error('S3のオブジェクトを取得できない');

    s3Mock
      .on(GetObjectCommand, {
        Bucket: 'dummyBucket',
        Key: 'dummyKey',
      })
      .rejects(error);

    expect(await main()).toEqual(error);
  });
});
  • テスト実行結果。
## @swc/jest
$ jest --coverage
 PASS  src/main.spec.ts
  S3のオブジェクトを取得できる
    ✓ 成功 (31 ms)
    ✓ 失敗 (3 ms)
  S3のオブジェクトを取得できない
    ✓ 成功 (3 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |
 main.ts  |     100 |      100 |     100 |     100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        1.324 s
Ran all test suites.
✨  Done in 2.53s.

## ts-jest
$ jest --coverage
 PASS  src/main.spec.ts (5.189 s)
  S3のオブジェクトを取得できる
    ✓ 成功 (28 ms)
    ✓ 失敗 (4 ms)
  S3のオブジェクトを取得できない
    ✓ 成功 (3 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |
 main.ts  |     100 |      100 |     100 |     100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        5.498 s
Ran all test suites.
✨  Done in 6.71s.

結果

@swc/jest は、「2.53s」。 ts-jest は、「6.71s」という結果になりました。

ts-jestと比べて、倍以上早くなりましたね。

@swc/jestを使って困ることがあるかどうか現段階では見えていませんが、まずは使ってみて様子を見てみようと思います。

14
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?