jestとは
Node.jsをテストするためのライブラリ
<公式ドキュメント> https://jestjs.io/docs/en/getting-started
※Node.jsのテストアプリとしては、他にもmocha(https://mochajs.org/ )が有名。
テストコードが必要な理由
・開発の時間短縮。コードを変更した後でも、テストコマンドを打つだけで自動的にテストしてくれる
・より信頼性の高い(バグの少ない)コーディングができる
・リファクタリングや機能の追加・削除が簡単にできる
アプリをテストするための準備
●jestのインストール
npm i jest
※npmでのjestのページ ( https://www.npmjs.com/package/jest )
●テスト用の環境を設定する
※本番用の環境がすでに「dev.env」にまとめられている場合
・ファイル構成
└── App
├── config //環境を保存するフォルダ
| ├── dev.env //本番用環境のための環境変数を格納しているファイル
| └── test.env //テスト環境のための環境変数を格納しているファイル
・test.envの設定
PORT=3010MONGODB_URL=mongodb://127.0.0.1:27017/task-manager-api-test
※テスト用のデータベースと接続させるようにMongoDBの設定を記述する
●package.jsonの設定
"scripts":{"start":"node src/index.js","dev":"env-cmd -f ./config/dev.env nodemon src/index.js","test":"env-cmd -f ./config/test.env jest --watch" //test時に動かす環境を記述。},"jest":{"testEnvironment":"node"//jestでnodeのコードをテストすると記述},
※「scripts」に「test」を記述することで、ターミナルに「npm test」でテスト(ファイル名にtestと含まれているもの)を動かすようになる。
※「test」に「--watch」で、「npm test」後に、ターミナルでjestが開きっぱなしになる
expressをテストするためのnpmパッケージ
「super test」 https://www.npmjs.com/package/supertest
・テストコード
constapp=require('./app') //portをlistenする以外のアプリの処理を読み込みrequest(app).expect(...)//アプリが立ち上がっていなくてもexptectでテストできる
→super testパッケージを用いると、アプリが立ち上がっていなくてもテストを行うことができる
通常のテスト
・testのためのファイル構成
└── App
├── test //テストを保存するフォルダ
| └── fixture //テスト環境のための環境変数を格納しているファイル
| ├── db.js //テスト用データをデータベースに格納するためのファイル
| └── async.test.js //テストコードを記述するファイル
●通常のテスト
・first.test.js
test('テストケース名',()=>{テストしたい関数}) //正常なら処理完了するテストtest('テストケース名',()=>{thrownewError('エラー') //正常ならエラーを返したいテスト項目})
jestでは通常、上記の書き方でテストコードを書く。
「npm test」でテスト開始。ファイル名に「test」が含まれているテストファイルが実行される。
非同期処理のテスト
・async.test.js
test('Async test demo',(done)=>{ //引数にdoneを設定setTimeout(()=>{expect(1).toBe(2)done() //非同期処理(ここではsetTimeout)が終わるタイミングでdoneを呼び出す},2000)})
↓
今回のテストでは、「setTimeout」をすると「1」が「2」になるかテストしている
↓
2秒後にエラーが返る。
※「toBe」について: jest公式ドキュメント
非同期処理のテストは、非同期処理が終わった時点で引数doneを呼び出すように設定しないと、ちゃんとテストされない(非同期処理を待たずにテストをパスしてしまう)
●Promiseを使うコードのテスト
constadd=(a,b)=>{returnnewPromise((resolve,reject)=>{setTimeout(()=>{if(a<0||b<0){returnreject('Number must be non-negative')}resolve(a+b)},2000)})}
上記のコードをテストする場合
・promise.test.js
test('addは機能しているか',(done)=>{add(2,3).then((sum)=>{ //thenを使ってチェインさせるexpect(sum).toBe(5)done()})})
async/awaitを使ってテストする場合
test('addは機能しているか、async/awaitで',async()=>{constsum=awaitadd(11,22)expect(sum).toBe(33)})
テストの前に行う処理・テストの後に行う処理を記述する
「Setup and Teardown」を用いる。
beforeEach(() => {
initializeCityDatabase();
});afterEach(() => {
clearCityDatabase();
});
・beforeEach:テストの前に行う処理を記述する
・afterEach:テストの後に行う処理を記述する
例)テストの前に、テスト用データベース内の全ての項目を消す
・users.test.js
constUser=require('../src/models/user')constuserOne={//テストデータ用のデータベースの中身neme:'aaa',password:'12345'}beforeEach(async()=>{ //beforeEachは非同期処理awaitUser.deleteMany() //データベースの中身を削除awaitnewUser(userOne).save()//空になったデータをデータベースに保存})
ライブラリのmockを作成する
・jest公式ドキュメント
Mocking Node Modulesを参照
・mockライブラリを作成する場合のファイル構成
└── App
├── test //テストを保存するフォルダ
| └── fixture //テスト環境のための環境変数を格納しているファイル
| | ├── db.js //テスト用データをデータベースに格納するためのファイル
| | └── test.js//テストコードを記述するファイル
└── __mocks__ //モックファイルを記述
└── sendgrid //モックを作成するAPI名
└── test.js
・test.js
module.exports={send(){}}
↓
今回はsendgridという、メール送信のためのライブラリ(https://sendgrid.com/docs/api-reference/)のモックを作成している。
コード中に「sgMail.send()」でメール送信をする箇所があった場合、テスト環境では作成したモックのsendgridが実行されるため、「send()」の処理は上記のファイルに書かれた通りのもの(今回の場合は何もしないこと)になる。