SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

実践! ユニットテスト入門

【実践的ユニットテスト入門】今からでも遅くない! ソフトウェアの最小単位を自動でテストする

実践! ユニットテスト入門 第1回

  • X ポスト
  • このエントリーをはてなブックマークに追加

ユニットテストを書いてみよう

 今回は人気のプログラミング言語であるTypeScriptを用いて、ユニットテストの実例を紹介します。

 TypeScriptでテストを実施する場合、Jestというテストフレームワークを利用するのが一般的です。しかし、セットアップに少し手間がかかるため、今回は簡単に環境構築ができるDeno(ディノ)を使用します。Denoにはテストランナーが同梱されており、特別なセットアップが不要であるためです。

 ただ、本記事では特定のプログラミング言語やテストフレームワークに限定されない考え方を紹介すること、また後述するように「準備、実行、値の検証」というテストの構成自体は同じであるため、ツールの違いによる大きな差異は特にないと考えていただいて問題ありません。

Deno をインストールする

 ここからは実際に手を動かしましょう。なお、以下の記述は執筆時点(2024年7月)のものであるため、環境構築のための最新情報はDenoの公式ドキュメントをご覧ください。

 まずDenoをインストールします。Macの方はターミナルから以下のコマンドを実行してください。

 curl -fsSL https://deno.land/install.sh | sh

 Windowsの方は以下のコマンドです。

 irm https://deno.land/install.ps1 | iex

  筆者はMacを用いているので、以下はMacのコマンドで記述していきます。

  次に$ deno --versionのコマンドを実行してください。以下のような結果が表示されればインストールは完了です。

 $ deno --version
 deno 1.44.1 (release, aarch64-apple-darwin)
 v8 12.6.228.3
 typescript 5.4.5

  各バージョンについて、Denoはv1.43.3、V8(JavaScript のコードを解釈し、実行するエンジン)はv12.6.228.3、TypeScript は v5.4.5 がインストールされていることがわかります。今回は基本機能のみを用いるため、もしお手元のバージョンが違っていても動作に問題はありません。

テスト対象のコードを書く

  では、コードを書いていきましょう。まずテスト対象となる関数を書いていきます。

 unit-testというディレクトリを作成し、ここをルートディレクトリとします。

  次に、unit-test配下にunit.tsファイルを作成します。今回は足し算の関数をテストするため、以下のように関数を定義します。

ts
 export function add(a: number, b: number) {
   return a + b
 }

  これでテスト対象となる関数の準備ができました。テストで動作を確認する対象は、一般的にプロダクションコードやテスト対象と呼ばれるので覚えておきましょう。

テストコードを書く

  次にテストコードを書きます。テストコードはテスト対象とは別のファイルに書くことがほとんどのプログラミング言語で一般的です(ただし、Rustは同じファイルにテスト対象もテストも書くそうです)。

  今回はunit.test.tsファイルを作成し、以下のようにテストを書いてみましょう。

ts
 import { assertEquals } from "https://deno.land/std@0.224.0/assert/mod.ts";
 import { add } from "./unit.ts"; // 1

 Deno.test("1 + 2 は 3 である", () => { // 2
   const x = add(1, 2); // 3
   assertEquals(x, 3); // 4
 });

  テストコードを丁寧に解説します。 まず、コードコメント1の行のimportは、TypeScriptのモジュールシステム上の記法で、別ファイルで定義された変数、関数、クラスを呼び出すことができるものです。

 unit.tsファイルでexport function add(..)のようにexportと記述したため、関数addは別ファイルであるunit.test.tsファイルからも呼び出すことができます。

  次に、コードコメント2の行のDeno.testはテストケースを記述するための関数です。第一引数でテストケース名を受け取り、第二引数では関数形式でテスト内容を受け取ります。

  コードコメントの3の行では、関数addに数値1、2を渡しています。実行結果は変数xに格納されています。 コメントの4の行のassertEqualsはDenoが用意している関数です。これは、テストで自分が期待する結果と実際の結果を比較するために使われます。このような特別な関数は一般的にアサーション(assertion)と呼ばれます。

  中でも、assertEqualsは引数として渡した二つの値が同じであることを確認する関数です。ここでは変数xが数値の3と一致するかチェックしています。一般にこのxは「実際の値(actual)」、3は「期待する値(expected)」と呼ばれます。

テストを実行して結果を確認する

  テストコードを書き終えたので、テストを実行してみましょう。unit-testディレクトリに移動し、$ deno testを実行してください。

 $ deno test
 Check file:///Users/panda/unit-test/unit.test.ts
 running 1 test from ./unit.test.ts
 1 + 2 は 3 である ... ok (0ms)

 ok | 1 passed | 0 failed (1ms)

  ok という表示が出ることで、テストは無事に実行され、テスト対象が期待通りの動きをすることがわかりました。このことを「テストが通る(Pass した)」といいます。

  もし実際の値と期待する値が異なる場合にどう動くか確かめてみましょう。unit.tsの関数addの足し算をする箇所を引き算に変えてみます。

ts
 export function add(a: number, b: number) {
   return a - b // add関数なのに引き算をしている
 }

  このコードで$ deno testを実行してみます。

 $ deno test
 Check file:///Users/panda/unit-test/unit.test.ts
 running 1 test from ./unit.test.ts
 1 + 2 は 3 である ... FAILED (1ms)

  ERRORS

 1 + 2 は 3 である => ./unit.test.ts:4:6
 error: AssertionError: Values are not equal.

 [Diff] Actual / Expected
 -   -1
 +   3

 throw new AssertionError(message);
   	^
   at assertEquals (https://deno.land/std@0.224.0/assert/assert_equals.ts:52:9)
   at file:///Users/panda/unit-test/unit.test.ts:6:3

 FAILURES

 1 + 2 は 3 である => ./unit.test.ts:4:6

 FAILED | 0 passed | 1 failed (2ms)

 error: Test failed

  実行結果は少し長いですが、恐れずに主要な部分を確認していきましょう。

 1 + 2 は 3 である ... FAILED (1ms)

  まず、上記の部分からテストがpassしたのではなくfailedになったことがわかります。日本語ではこれを「テストが失敗した」と表現します。

 error: AssertionError: Values are not equal.

 [Diff] Actual / Expected
 -   -1
 +   3

  次にこの出力内容を見ると実行結果は-1である一方、期待する値が3であるため値がズレているということがわかります。よって、テストコードの実装者は数値の3が返ってくることを期待したのに実際は-1が返ってきたということがわかります。これでテストが失敗したときどのようなことが起きるかがわかりました。この情報から、テスト対象のコードにバグが含まれていることがわかります。

  最後に、テストを通すためにadd関数を元の足し算に戻して$ deno testを再度実行しましょう。

ts
 $ deno test
 running 1 test from ./unit.test.ts
 1 + 2 は 3 である ... ok (0ms)

 ok | 1 passed | 0 failed (1ms)

  なお、add関数のみだとロジックが単純すぎてテストコードのイメージを持ちにくいため、記事の最後にFizzBuzzの実装とそのテストを掲載します。よければそちらもご覧ください。

次のページ
今日からテストを実践するための知識

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
実践! ユニットテスト入門連載記事一覧
この記事の著者

プログラミングをするパンダ(プログラミングヲスルパンダ)

 https://twitter.com/Panda_Program/ フロントエンドエンジニア。元々サーバーサイドエンジニアだったが、個人開発を機に HTML, CSS, JS に興味を持つ。特に React、Next.js に熱中しフロントエンジニアに転向。TDD、XP、DevOps が好き。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/19854 2024/07/22 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング