どのプログラミング言語でも、開発の過程でテストを行うことは重要です。JavaScriptでは、テストフレームワークとしてJestが幅広く利用されています。
今回は、Jestを使ったテストコードの書き方について解説していきます。
はじめてのテスト
まずは、任意の名前でフォルダを作成し、その中にJestをインストールしておきます。
sum.jsの作成
準備が整ったらsum.jsというファイルを作成し、その中に2つの引数を加算するかんたんな関数を書きます。
function sum(a, b) {
return a + b;
}
module.exports = sum;
sum.test.jsの作成
次に、sum.test.jsファイルの作成です。
Jestでは、.test.js
という名前のファイルをテストコードとして認識します。
今回は、sum.jsというファイルをテストするため、テストコード用のファイルにはsum.test.jsと名前を付けます。
sum.test.jsファイルの中に以下を記述します。
const sum = require('./sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
何をテストしているのか、なんとなくイメージができるのではないでしょうか。
Jestの構文は以下で説明しますが、かんたんに言うと、上記はsum(1, 2)
の結果が3であるかどうかチェックをしています。
テストの実行
それではテストを実行してみましょう。
ターミナルでyarn test
コマンドを入力すると、以下のようにテストが通ったことが確認できます。
$ yarn test
PASS ./sum.test.js
✓ adds 1 + 2 to equal 3 (2 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.749 s
Ran all test suites.
✨ Done in 2.73s.
反対に、sum.jsのコードをテストが通らないように変更すると以下のようなメッセージが表示されます。
$ yarn test
FAIL ./sum.test.js
✕ adds 1 + 2 to equal 3 (8 ms)
● adds 1 + 2 to equal 3
expect(received).toBe(expected) // Object.is equality
Expected: 3
Received: 4
...
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 0.742 s, estimated 1 s
Ran all test suites.
FAILと書かれているように、今度はテストが通らなかったことが分かります。
Expected: 3
とReceived: 4
を見てください。
このコードの場合、テストが期待する結果は3ですが、関数が返した実際の結果は4です。
このようにJestでは、どの部分が失敗しているのか内容が表示されるようになっています。
Jestの基本構文
Jestの基本構文は以下です。
test('テストの説明', () => {
expect(テスト対象の値やオブジェクト).matcher(テスト対象に期待する結果);
});
一つずつ構成を見ていきましょう。
test
testブロックには、どのようなテストを行なっているのかパッと見て分かる説明文を書きます。
説明文は、英語であればすべて小文字を使い、現在形を用います。日本語の場合は特別意識する必要はありません。
expectとmatcher
expect関数には、テスト対象となる値やオブジェクトを記述します。
その後ろにあるmacherには、テスト対象の値やオブジェクトに期待する結果を記述します。
これにより予期するものが返ってくるかチェックすることができます。
macher
macherには、さまざまな種類が用意されており、目的によって使い分けることができます。
以下は代表的なmatcherです。
プリミティブ型・オブジェクト型チェック
まずは、もっとも一般的なmatcherです。
どちらも厳密に等価性があるかをチェックしますが、対象は以下の通りです。
- toBe:プリミティブ型のチェック
- toEqual:オブジェクト型のチェック(オブジェクトや配列)
// プリミティブ型
test('three plus two is five', () => {
expect(3 + 2).toBe(5);
});
// オブジェクト型
test('check object', () => {
const obj = { 1: 'one', 2: 'two'};
expect(obj).toEqual({ 1: 'one', 2: 'two'});
});
また、macherの前に.not
と記述すると、matcherと一致しないかをチェックすることが可能です。
test('2 + 2 = 10ではない', () => {
expect(sum(2, 2)).not.toBe(10);
});
null・undefined・真偽値チェック
- toBeNull:値がnullかチェック
- toBeDefined:値が定義されているかチェック
- toBeUndefined:値がundefinedかチェック
- toBeTruthy:値がtrueかチェック
- toBeFalsy:値がfalseかチェック
// null
test('test null', () => {
const n = null;
expect(n).toBeNull();
});
// defined, undefined
test('test defined + undefined', () => {
let u, d = 1;
expect(d).toBeDefined();
expect(u).toBeUndefined();
});
// true, false
test('test boolean', () => {
expect(1 + 1 === 2).toBeTruthy();
expect(1 + 1 === 3).toBeFalsy();
});
数値チェック
- toBeGreaterThan:値が大きいかチェック
- toBeGreaterThanOrEqual:値が大きいか、または等しいかチェック
- toBeLessThan:値が小さいかチェック
- ToBeLessThanOrEqual:値が小さいか、または等しいかチェック
test('one plus one', () => {
const v = 1 + 1;
expect(v).toBeGraterThan(1);
expect(v).toBeGreaterThanOrEqual(1.5);
expect(v).toBeLessThan(3);
expect(v).toBeLessThanOrEqual(2.5);
});
JavaScriptの数値はフロート値(64ビットの浮動小数点)で計算されています。
そのため、一見整数を扱っているように見えても、小数点を用いたフロート値であることから、数値の比較や計算において思っていた結果にズレが生じることがあります。
例えば以下のようなコードです。
console.log(0.1 + 0.2 === 0.3); // false
console.log(0.1 + 0.2); // 0.30000000000000004
わずかな誤差によって問題が起きてしまうのを防ぐために、フロート値を比較する場合は、toEqual
ではなく、toBeCloseTo
を利用しましょう。
test('test tobecloseto', () => {
expect(0.1 + 0.2).toBeCloseTo(0.3);
});
文字列チェック
- toMatch:正規表現で文字列をチェック
test('test string', () => {
const regexp = /^([^@s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})$/i;
expect('sample@testmail.com').toMatch(regexp);
});
配列チェック
- toContain:配列に特定の値が含まれているかチェック
test('test array', () => {
const colors = ['red', 'blue', 'yellow'];
expect(colors).toContain('red');
expect(colors).not.toContain('pink');
});
まとめ
今回は、Jestを用いたテストコードの書き方について解説しました。
Jestの基本的な使い方と利用できるmatcherの理解ができれば、さらに実践的なテスト駆動開発ができるようになります。
まずは基本をしっかりとおさえていきましょう。
合わせて読みたいテストシリーズ
第1回:テストフレームワーク -Jest
第2回:テストコードの書き方(当記事)
第3回:テスト駆動開発
コメント