Node.js テストツール


#Node.jsテストツール

##Mocha
　ユニットテスト用に使うのじゃ･･･
　テストコードを軽く記述しておいて、入力値と返り値が等しいかチェックするのじゃ･･･

```javascript:Mocha
it('should add two numbers', () => {
  var result = utils.add(33, 11);
  if(result !== 44){
     throw new Error(`44のはずが,結果が${result}だった`);
  }
}
```

　上記のようにitを使用してテストを記述するのじゃ･･･
　英語で書くと　"it ~"と文になるのが特徴らしいのじゃ･･･

##Expect
　Mochaに組み合わせて使用するのじゃ･･･
　なんでかというと、いちいちifとかで場合分けしてエラーを投げるのがアホらしいので、Expectを使ってより簡単に書こうというわけじゃな・・・

```javascript:Expect
it('should add two numbers', () => {
    var result = utils.add(33, 11);

    // if(result !== 44){
    //     throw new Error(`44ののはずが、${res}だった！`);
    // }

    expect(result).toBe(44).toBeA('number');

});
```

　記法は上の用になるのじゃ･･･
　const expect = require('expect')で読み込んでおいて、expectの引数に確かめたいものをぶち込めば良いわけじゃな･･･
　その後は、メソッドチェーン記法で、テストしたい内容を書き連ねればいいのじゃ･･･
　もし想像していない動作が合ったら、自動でコンソール上にエラーを吐くのじゃ･･･

##Supertest
　Supertestはこれまでの一つ一つのモジュールチェック用ではなく、expressのサーバーのテスト用に使用するらしいのじゃ･･･
　get要求やpost要求など、それぞれの要求に対してチェックしたいことを書いておけるらしいのじゃ･･･

```javascript:Supertest

const request = require('supertest');
const expect= require('expect');

//module.exports.appに入れておいたapp.jsを取り出す
var app = require('./app.js').app;

it('should return a name', (done) => {
    request(app)
        //./usersにget要求されたとき
        .get('/users')
        //200（成功）のはず
        .expect(200)
        //応答リクエストの中身はオブジェクト形式でname,ageを含むはず
        .expect((res) => {
            expect(res.body).toInclude({
                name:'hogehoge',
                age: 20
            })
        })
        //非同期処理のテストの際にがdoneでキチンと終了を知らせる
        .end(done);
})

```

#インストール

```console
$ npm install --save-dev expect
$ npm install --save-dev mocha
$ npm install --save-dev supertest
```

#コード

##検査されるファイル1 utils.js
```javascript:utils.js

module.exports.add = (a, b) => {
    return a + b;
}

module.exports.square = (x) => {
    return x * x;
}

module.exports.setName = (user, fullName) => {
    var names = fullName.split(' ');
    user.firstName = names[0];
    user.lastName = names[1];
    return user;
}

module.exports.asyncAdd = (a, b, callback) => {
    setTimeout(()=>{
        callback(a+b);
    }, 1000)
}

//コールバックはC++でいうインターフェイスに近い
//定義自体は呼び出し元に記述する
module.exports.asyncSquare = (x, callback) =>{
    setTimeout(()=>{
        callback(x*x);
    }, 1500)
}
```

##検査するファイル1 utils.test.js

```javascript:utils.test.js


const expect = require('expect');
const utils = require('./utils');



//テストに名前をつける
//describeは階層構造にできる
describe('ユーティリティテスト', () => {

    describe('#Not Async', () => {
        it('should add two numbers', () => {
            var result = utils.add(33, 11);

            // if(result !== 44){
            //     throw new Error(`44ののはずが、${res}だった！`);
            // }

            expect(result).toBe(44).toBeA('number');

        });

        it('should square a number!', () => {
            var result = utils.square(10);

            expect(result).toBe(100).toBeA('number');

        })


        it('should expect some values', () => {

            expect({
                name: 'hogehoge',
                age: 25,
                location: 'tokyo'
            }).toInclude({
                name: 'hogehoge',
                age: 25
            })
        })

        it('should be the same name', () => {

            var fullName = 'hoge piyo';
            var names = {
                firstName:'hoge',
                lastName:'piyo'
            }
            var results = utils.setName(names,fullName)

            expect(results).toInclude({
                firstName: 'hoge',
                lastName: 'piyo'
            })

        })

    })

    describe('#Async', () => {
        //コールバック関数に、doneを取ると、doneが実行されるまでチェックを行う
        it('should add two numbers async', (done) =>{

            utils.asyncAdd(20, 30, (sum) => {
                expect(sum).toBe(50).toBeA('number');
                done();
            })

        })



        it('should square a number async', (done) => {

            utils.asyncSquare(10, (sum) => {
                expect(sum).toBe(100).toBeA('number');
                done();
            })

        })

    })



})


```

##検査されるファイル2 server.js

```javascript:server.js

const express = require('express');

var app = express();


app.get('/', (req, res, next) => {
    res.status(200).send({
        name: 'hogehoge',
        title: 'title'
    })
})


app.get('/users', (req, res, next) => {
    res.status(200).send({
        name: 'hogehoge',
        age: 20
    })
})


app.listen(3000);

module.exports.app = app;  //検査できるようにexportする
```

##検査するファイル2 server.test.js

```javascript:server.test.js

const request = require('supertest');
const expect = require('expect');

var app = require('./server.js').app;


describe('サーバーテスト', () => {

    describe('#GET /', () => {
        it('should return hello world response', (done) => {
            request(app)
                .get('/')
                .expect(200)  //Status
                .expect((res) => {
                    expect(res.body).toInclude({
                        name: 'hogehoge'
                    })
                })
                .end(done);
        })
    })

    describe('#GET /users', () => {
        it('should return a name', (done) => {
            //supertest→request
            //引数はapp(元のmodule.exportから受け取る)
            request(app)
                .get('/users')
                .expect(200)
                .expect((res) => {
                    expect(res.body).toInclude({
                        name:'hogehoge',
                        age: 20
                    })
                })
                .end(done);
        })
    })


})
```

#参考文献
[Mocha](https://mochajs.org/)
[expect](https://github.com/mjackson/expect)
[supertest](https://github.com/visionmedia/supertest)