Serverless Frameworkで行う継続的インテグレーションのススメ

## 概要
サーバレス構成でサービスを構築する際に便利な<a href="http://serverless.com/">Serverless Framework</a>ですが、コアからユニットテストを回すための方法は提供されていません。自分たちでテストの枠組みを定義する必要があります。今回はその方法の紹介です。

## テスト対象のLambdaファンクションを作成する
以下のコマンドにてLambdaファンクションを作成します。今回は例としてhelloというファンクションを作ってみます。
```
$ serverless function create hello
```

すると以下の様なディレクトリ構成が出来上がります。

```
├── hello
│   ├── event.json
│   ├── handler.js
│   └── s-function.json
```

`handler.js`が実際にLambdaとして実行されるファイルなのですが、初期状態では以下の様な内容になっています。

```js
module.exports.handler = function(event, context, cb) {
  return cb(null, {
    message: 'Go Serverless! Your Lambda function executed successfully!'
  });
};
```

実行させると以下のように`Go Serverless! Your Lambda function executed successfully!`というメッセージが返ってきます。
<img width="550" alt="スクリーンショット 2016-06-14 0.06.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/65478/f8e9edfb-c2b4-8c7b-93a7-8000f459061a.png">



## UnitTestの構成を作る
今回はJavaScriptのテスティングフレームワークとして有名な`mocha`と`chai`を使います。
まずはそれらをServerlessプロジェクト内にインストールします。

`--save-dev`オプションを指定して、package.jsonのdevDependenciesに登録しておくとよいでしょう。

```js
$ npm install chai --save-dev
$ npm install mocha --save-dev
```

`tests/all.js`というファイルをプロジェクトのルート階層に作ります。

```
├── hello
│   ├── event.json
│   ├── handler.js
│   └── s-function.json
└── tests
    └── all.js
```

テストコードは以下のとおり
テストコード内でLambdaファンクションを実行させて返り値を比較させます。

```js:tests/all.js
'use strict';
// Unit tests for Serverless
// Generated by Serverless UnitTestBoilerplate
var s
const path       = require('path'),
      chai       = require('chai'),
      should     = chai.should(),
      Serverless = require('serverless')
      
describe('ServerlessProjectTest', function() {
  beforeEach(function(done) {
    this.timeout(0);

    s = new Serverless();

    s.init().then(function() {
      s.config.projectPath = __dirname + '/../';
      s.setProject(new s.classes.Project({
        stages: {
          dev: { regions: { 'ap-northeast-1': {} }}
        },
        variables: {
          project: 'serverless-project',
          stage: 'dev',
          region: 'ap-northeast-1'
        }
      }));
      
      s.getProject().setFunction(new s.classes.Function(
        {
          name:"hello",
          runtime:"nodejs4.3"
        },
        __dirname + '/../hello/s-function.json'));
 
      done();
    });
    
  });
  
  describe('#funciton hello()', function() {
    it('should be funciton hello success', function() {
      return s.getProject().getFunction('hello').run('dev', 'ap-northeast-1', {})
      .then(result => {
        result.response.message.should.equal('Go Serverless! Your Lambda function executed successfully!')
      });
    });
  });
});

```

そして、package.jsonに以下を追記すれば準備完了です。

```
├── package.json
├── hello
│   ├── event.json
│   ├── handler.js
│   └── s-function.json
└── tests
    └── all.js
```

npmでグローバルインストールされているserverlessにpathを通すためexportさせています。

```json:package.json
"scripts": {
    "test": "export NODE_PATH=`npm root -g` && mocha tests/all"
}
```

テストを実行してみましょう。`npm test`の結果以下のとおり、正しくテストが実行されました。
<img width="558" alt="スクリーンショット 2016-06-14 0.21.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/65478/aaf0e4f0-5013-166e-3201-e3f5ffc53be4.png">


## Travisで実行させる
TravisでGitにpushしたタイミングでテストが実行されるようにしてみましょう。
プロジェクトのルート階層に.travis.ymlを設置します。

```
├── .travis.yml
├── package.json
├── hello
│   ├── event.json
│   ├── handler.js
│   └── s-function.json
└── tests
    └── all.js
```

ファイルの内容は以下のとおり

```yaml:.travis.yml
language: node_js

node_js:
  - '4'

sudo: false

install:
  - npm install -g serverless
  - npm install

script:
  - npm test
```

そして、Travis側の設定を行い、gitにpushすると以下のとおりテストを実行してくれました。
https://travis-ci.org/horike37/serverless-deployment-cycle/builds/136548908


##  今回のテストコードを生成してくれる機能をServerlessのプラグインとして公開しました
[Serverless UnitTest Boilerplate](https://github.com/horike37/serverless-unittest-boilerplate)として公開しています。詳しい使い方はREADMEに記載しています。興味の有る方は是非使ってみてください！