Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8837

Mocha, Chaiを使ったテストの表記パターン

$
0
0

TypeScriptでMocha, Chaiを使ったテスト駆動開発

インストール

TDDをサポートしてくれるパッケージのインストール。
$ npm install chai mocha ts-node @types/chai @types/mocha --save-dev

参考: Testing TypeScript with Mocha and Chai

しかし、私の場合なぜかTypeScriptをグローバルインストールしているにも関わらず、テスト実行時に「typescriptモジュールが見つからない」とエラーが出てしまうので、ローカルに開発インストールを行いました。よってコマンドは以下になります。

テスト実行時のエラー例
✖ ERROR: Cannot find module 'typescript'# typescriptが見つからない、とエラーが出る場合のインストール。$ npm install typescript chai mocha ts-node @types/chai @types/mocha --save-dev

package.json

(typescriptを含めた場合)最小限でこのようなpackage.jsonになるはず。
"scripts"下の"test"コマンド定義部分は"test"ディレクトリの下にあるファイル名が".ts"で終わるファイルを全て変更監視の対象にする場合の例です。対象のファイルが変更された場合には自動でtscによるコンパイルが行われ、テストが実行されます。

package.json
{"name":"testPatterns","version":"1.0.0","description":"samples for test cases.","main":"index.js","scripts":{"test":"mocha --require ts-node/register --watch-extensions ts \"test/**/*.ts\""},"author":"@olisheo","license":"ISC","dependencies":{},"devDependencies":{"@types/chai":"^4.2.5","@types/mocha":"^5.2.7","@types/node":"^12.12.12","chai":"^4.2.0","mocha":"^6.2.2","ts-node":"^8.5.2","typescript":"^3.7.2"}}

前記した通り、上記は"typescript"がローカルインストールされている状態で、なぜかこれが必要でした。

シンプルなテストで動作確認

テストの実行コマンド
$ npm test---w

シンプルなテスト

とりあえず一番シンプルなテストで動作を確認する。パスするケースと、失敗するケースを一つづつ用意。

describe('simplest test:',()=>{it('1 + 1 should be 2',()=>{expect(1+1).to.equal(2);});it('the test should fail because it expects "1 + 1 = 0"',()=>{expect(1+1).to.equal(0);});});
実行と結果
$ npm test---w> testPatterns@1.0.0 test /Users/user/project/testPatterns
> mocha --require ts-node/register --watch-extensions ts "test/**/*.ts""-w"

  simplest test:
    ✓ 1 + 1 should be 2
    1) the test should fail because it expects "1 + 1 = 0"


  1 passing (18ms)
  1 failing

  1) simplest test:
       the test should fail because it expects "1 + 1 = 0":

      AssertionError: expected 2 to equal 0
      + expected - actual

      -2
      +0

想定通り、一つはパスして一つはフェイルしてます。

よく使うパターン

同期処理で例外が投げられたらパス

describe('Typical tests:',()=>{it('immediate exception should synchronously be thrown.',()=>{expect(()=>{// 想定通りならば例外が発生するケースを記述。例えば下のように例外が投げられればパスする。// throw new Error('just expected exception.');  }).to.throw();});});

非同期処理をawaitで待つ

describe('Typical tests:',()=>{it('using await, timer should successfully expires',async()=>{constexpirationMessage=awaitsetTimer(1000);expect(expirationMessage).equals('OK!');});});// テスト対象の非同期関数。functionsetTimer(msec:number):Promise<string>{returnnewPromise((resolve,reject)=>{setTimeout(()=>{resolve('OK!');},msec);});}

Promiseを使った非同期。

Promiseをリターンで返すことで、Mochaが持っているPromiseのサポートを使える。しかし表記ミスを避けるために、できる限り前期のawaitを使った表記がいいと思う。ちなみにPromiseをリターンしないと、フェイルするテストがパスしてしまう。

describe('Typical tests:',()=>{it('using promise, timer should always be rejcted after timeout.',()=>{returnsetRejectionTimer(2000).then((expirationMessage)=>{expect.fail('test fails because the test case expects rejection.');}).catch((e)=>{expect(e).to.equal('NOT OK!');});});});// テスト対象の非同期関数。functionsetRejectionTimer(msec:number):Promise<string>{returnnewPromise((resolve,reject)=>{setTimeout(()=>{reject('NOT OK!');},msec);});}///////////////// これはだめ! /////////////////////////////describe('Typical tests:',()=>{it('using promise, timer should always be rejcted after timeout.',()=>{// 下は間違い。Primiseはリターンで返さないといけない。setRejectionTimer(2000).then((expirationMessage)=>{expect.fail('test fails because the test case expects rejection.');}).catch((e)=>{expect(e).to.equal('NOT OK!');});});});

実は上記の動くバージョンでも本質的なテストにはなっていなくて、Promiseがrejectされなかった場合は、expect.fail('test fails because the test case expects rejection.') で例外を発生させているため、expect(e).to.equal('NOT OK!')の条件と合致してテストがパスしているのであって、expect.fail()を削除して例外を発生させてなければ、フェイルするべきテストもパスしてしまう。

非同期はto.throw()が使えなさそう。

以下も機能しない。

非同期関数内でrejectが発生してもテストはパスしない。
describe('Typical tests:',()=>{it('delayed exception should asynchronously be thrown.',()=>{expect(async()=>{awaitsetRejectionTimer(3000);}).to.throw();// 機能しない。});});

タイムアウトを回避したい場合のテスト実行コマンド

実行時間がかかるテストも多いので、タイムアウトを延ばすためのオプションはよく使います。

--timeoutパラメーターで30秒のタイムアウトを指示した場合。
$ npm test---w--timeout 30000

これから

「非同期処理の中で例外が起こること」を正確にアサートするのは、現状難しそうです。テスト対象にPromiseを扱いやすくするchai-as-promiseなるものがあるらしいので、時間を見つけて今度はそちらをかじってみたいと思います。


Viewing all articles
Browse latest Browse all 8837

Trending Articles