Deno入門[テスト編]

この記事は筆者の[ソロ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/panda) 18日目の記事です。

Denoの公式ドキュメントの内容を実際に動かしてみてDenoに入門してみたのでその備忘録の続きです。Deno入門の最後はテストコードを書いていきたいと思います。

[Deno入門[インストール、環境構築、ファイル実行、標準ライブラリ]](https://qiita.com/JY8752/items/9cd6c05394bf955bdd75)
[Deno入門[CLIコマンド、モジュール、環境変数、Webフレームワーク]](https://qiita.com/JY8752/items/a00866917626a8719ebb)
[Deno入門[npmモジュールの使用]](https://qiita.com/JY8752/private/d177e176a7544b693a34)
[Deno入門[prisma + oakで作るAPI]](https://qiita.com/JY8752/private/198762a69d463ac90fab)
[Deno入門[テスト編]](https://qiita.com/JY8752/private/e7e52aae6a0a3eb69572)　<- 今ここ

# Denoでテストを書く
Denoでは標準で以下のように組み込みのtestメソッドを使用することで簡単にテストを書くことができます。アサーションは標準ライブラリからインポートして使用することができます。

```typescript
import { assertEquals } from "https://deno.land/std@0.165.0/testing/asserts.ts";
import { add } from "./main.ts";

Deno.test(function addTest() {
  assertEquals(add(2, 3), 5);
});
```

実行はdeno testでターミナルから実行可能
```
deno test
addTest ... ok (10ms)
```

VSCodeを使用していて、Denoの拡張を入れている方であればVSCode上で実行することも可能。

テストの書き方は以下のように書くこともできる。

```typescript
import { assertEquals } from "https://deno.land/std@0.166.0/testing/asserts.ts";

// 第一引数にテスト名で第二引数をアロー関数で記述
Deno.test("hello world #1", () => {
  const x = 1 + 2;
  assertEquals(x, 3);
});

// 関数名がテスト名
Deno.test(function helloWorld3() {
  const x = 1 + 2;
  assertEquals(x, 3);
});

// オブジェクトで指定
Deno.test({
  name: "hello world #2",
  fn: () => {
    const x = 1 + 2;
    assertEquals(x, 3);
  },
});

// パーミッション付きテスト実行
Deno.test("hello world #4", { permissions: { read: true } }, () => {
  const x = 1 + 2;
  assertEquals(x, 3);
});

// 上記の別の書き方
Deno.test(
  { name: "hello world #5", permissions: { read: true } },
  () => {
    const x = 1 + 2;
    assertEquals(x, 3);
  },
);

// 上記の別の書き方
Deno.test({ permissions: { read: true } }, function helloWorld6() {
  const x = 1 + 2;
  assertEquals(x, 3);
});
```

# データ駆動テストを書いてみる
筆者はデータ駆動テスト信者なのでテスト駆動テストを書いてみました。DenoでJestで書いてたようなテストを書くには標準ライブラリで用意されているbdd.tsモジュールを使用することができます。今回はテストをネストさせて実行させたかったのでbddモジュールから```describe```と```it```をインポートしてテストを書いてみると以下のようになります。

```typescript
import { assertEquals } from "https://deno.land/std@0.165.0/testing/asserts.ts";
import { describe, it } from "https://deno.land/std@0.167.0/testing/bdd.ts";
import { add } from "./main.ts";

describe("data driven test demo", () => {
  const testTable: {
    name: string;
    num1: number;
    num2: number;
    expected: number;
  }[] = [
    {
      name: "test1",
      num1: 1,
      num2: 1,
      expected: 2,
    },
    {
      name: "test2",
      num1: 2,
      num2: 2,
      expected: 4,
    },
  ];
  testTable.forEach(({ name, num1, num2, expected }) => {
    it(name, () => {
      assertEquals(add(num1, num2), expected);
    });
  });
});
```

Mapで書くとこんな感じ
```typescript
describe("data driven test demo2", () => {
  const testTable: Map<string, {
    num1: number;
    num2: number;
    expected: number;
  }> = new Map([
    [
      "test1",
      {
        num1: 1,
        num2: 1,
        expected: 2,
      },
    ],
    [
      "test2",
      {
        num1: 2,
        num2: 2,
        expected: 4,
      },
    ],
  ]);
  testTable.forEach(({ num1, num2, expected }, name) => {
    it(name, () => {
      assertEquals(add(num1, num2), expected);
    });
  });
});
```

変数宣言なしで書くとこう
```typescript
describe("data driven test demo3", () => {
  new Map([
    [
      "test1",
      {
        num1: 1,
        num2: 1,
        expected: 2,
      },
    ],
    [
      "test2",
      {
        num1: 2,
        num2: 2,
        expected: 4,
      },
    ],
  ]).forEach(({ num1, num2, expected }, name) => {
    it(name, () => {
      assertEquals(add(num1, num2), expected);
    });
  });
});

describe("data driven test demo4", () => {
  [
    {
      name: "test1",
      num1: 1,
      num2: 1,
      expected: 2,
    },
    {
      name: "test2",
      num1: 2,
      num2: 2,
      expected: 4,
    },
  ].forEach(({ name, num1, num2, expected }) => {
    it(name, () => {
      assertEquals(add(num1, num2), expected);
    });
  });
});
```

実行しても全部パスします
```
deno test
running 6 tests from ./main_test.ts
addTest ... ok (10ms)
url test ... ok (4ms)
data driven test demo ...
  test1 ... ok (5ms)
  test2 ... ok (3ms)
data driven test demo ... ok (15ms)
data driven test demo2 ...
  test1 ... ok (4ms)
  test2 ... ok (5ms)
data driven test demo2 ... ok (13ms)
data driven test demo3 ...
  test1 ... ok (3ms)
  test2 ... ok (3ms)
data driven test demo3 ... ok (10ms)
data driven test demo4 ...
  test1 ... ok (3ms)
  test2 ... ok (2ms)
data driven test demo4 ... ok (10ms)

ok | 6 passed (8 steps) | 0 failed 
```

:::note info
筆者はJestなどのJavaScritp(TypeScript)製のテスティングフレームワークの経験があまりないのでこんな感じかなという感じで書いてみましたが、こんな書き方できるよというのがあればぜひコメントください🙇‍♂️
:::

# まとめ
- Denoでのテストの書き方について簡単に紹介いたしました。
- Denoでのデータ駆動テストの書き方について紹介いたしました。

今回までの記事でDenoを使ったサーバー開発を簡単に触ってきましたが、思っていたよりも問題なく開発できるなと思いました。筆者はTypeScriptの実務経験はあまりないのでnpm initしてTypeScriptをインストールして、tsconfig.jsonを作成して...みたいな最初の雛形作成から毎回調べてやるくらいなのですが、Denoであれば手元の環境にDenoをインストールしてあればmain.tsからすぐに書き始めることができるのでnpmに慣れていない開発者でも抵抗なくTypeScriptを書き始められるのがめちゃくちゃいいなと今回の記事を書いて思いました！

npmモジュールに対応したことで今までのnpm資産をDenoでも使用できるようになったことで、ReactやVueのようなフロントフレームワークをそのまま使えるようになっていくと思いますし、FreshのようなDeno製のフロントフレームワークがくるのかもしれないですし、サーバー側であればよく聞くNestJSをDenoで使えるようになっていくかもしれないですし、oakのようなDeno製のライブラリが使用されるようになっていくかもしれません。

Denoが今後どのように発展していくかは筆者には予想できませんが、TypeScriptに馴染みのないサーバーサイドエンジニアがTypeScriptを触るにはDenoは大変いいと思います！まだ、TypeScriptをあまり触れていないという方はぜひDenoで触ってみてください！あと恐竜がかわいい


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551753/2e648ac0-e249-a3e6-0f24-aedc3b8cdb5d.png)
(create-vite-extraでdeno + Reactでプロジェクトを作成した時の初期画面Deno)

今回は以上です！