Node.jsの開発時に必要な情報(2020年9月更新)

<font color="red">**注意**</font>
この記事は、2014年の段階でNode.jsの開発時にデバッグ～継続的インテグレーションが行えるようにするために必要な情報をまとめていました。
その後、2020年08月にnode v12.18.3を対象に調査しなおしました。

# Node.jsのインストール方法

http://nodejs.org/

ここから、インストーラなりソースなり取得してインストールする。

Windows,Macはインストーラが存在している。
Windowsの場合、VS2008や、VS2012などの複数のVisualStudioが混在している環境だとnpm installが失敗することがあった。
その場合は、環境変数を調整してVisualStudioのバージョンを指定して動作するようにしておくこと。

# Node.jsのデバッグ方法(2020年)
https://nodejs.org/en/docs/guides/debugging-getting-started/

## ローカルのデバッグ
Visual Studio Codeでアプリケーションのあるフォルダを開いて実行すると、デバッグが可能

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/f4eed27c-ad28-cf17-0bf5-d16b4ed2d904.png)


## chromeを用いてリモートデバッグを行う方法
### 事前準備
下記の拡張機能をChromeにインストールする。

 - [NIM (Node Inspector Manager)](https://chrome.google.com/webstore/detail/nodejs-v8-inspector-manag/gnhhdgbaldcilmgcpfddgdbkhjohddkj)

### デバッグ方法
１. デバッグ対象のアプリケーションの起動方法

```
$ node --inspect=0.0.0.0 hello-world.js
Debugger listening on ws://0.0.0.0:9229/4d491e82-cd7a-4e4c-8ac0-914d14ab95d5
For help, see: https://nodejs.org/en/docs/inspector
Server running at http://192.168.0.100:3000/
```

２. chromeのNIM拡張機能を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/41be1dc4-8518-6b3c-83db-40d7aa81b0f9.png)

デバッグ対象のホストのアドレスとポートを入力後、「Open DevTools」を開く

３. Chromeでデバッグが行えるようになる。

**ブレイクポイントの例**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/28e80ada-d0ea-56ca-275d-dff7eb865df4.png)

**メモリの使用状況の例**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/9ebac521-cbdf-682a-1e65-02b870326b24.png)
Chromeの開発者ツールのメモリタブから調べることができる。

なお、かって存在したnode-webkit-agentについてはv0.12では使用できない。
https://github.com/c4milo/node-webkit-agent/issues/78

## ガベージコレクションを実行する方法
Node.jsは世代別のガベージコレクションなので、解放したつもりでもメモリが残っている場合がある。そのときは、任意のタイミングでガベージコレクトを行ったあと、メモリのスナップショットを確認する。

ガベージコレクションを確実に走らせたい場合は以下のような処理が必要である。
まず、プログラム中でガベージクレクタを実行したい箇所に次のコードを埋め込む。

```
if(global.gc) {
  global.gc();
}
```

gcを使用するにはアプリを起動する際に--expose_gcを指定すること。

```
node --expose_gc server.js
```

## console.logによるオブジェクトの出力
Console.logを用いることでオブジェクトをコンソールに出力することができるが、この際、一部の内容しか表示されない場合がある。

この場合はutilモジュールを用いることですべての内容を表示させることができる。

```
const util = require('util');
console.log(util.inspect(obj,false,null));
```

# 静的解析
実際にプログラムを実行しないで、リスクのある記述方法を検知することができる。
これらの処理はJenkinsなどで定期的に実行するとよい。

## eslintによる静的解析
2020年のnpmのトレンドとしてはeslintが優勢のようである。
https://www.npmtrends.com/jslint-vs-jshint-vs-jscs-vs-eslint

eslintについては以下のページを参照
https://eslint.org/


#### eslintをコマンドラインから使用する

１. 下記の通りインストールを行う。

```
npm install eslint --save-dev
```

※eslintをグローバルにインストールすることも可能ですが、これはお勧めされていません。
https://eslint.org/docs/user-guide/getting-started

２．解析対象のプロジェクトのpackage.jsonが存在することを確認する
存在しない場合は以下のコマンドで作成する。

```
npm init -y
```

３．eslintの設定ファイルを作成する。

```
npx eslint --init
```

上記のコマンドを実行することで対話形式で設定を行い.eslintrc.{js,yml,json}が作成される。

４．ファイルまたはフォルダを指定することで対象のファイルを解析できる。

```
npx eslint ~/nodejs/prj
```

その他の説明については下記を参照

**コマンドラインの説明**
https://eslint.org/docs/user-guide/command-line-interface

**設定ファイルの説明**
https://eslint.org/docs/user-guide/configuring

#### eslintをJenkinsで利用する
１．Warning Next Generationプラグインをインスト―ルする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/f52ddf0c-9b56-7055-2f3f-32f5a761fe35.png)

２．ジョブの設定を行う
２．１　ビルド中に下記のコマンドを実行して静的解析の結果をXMLに保存する

```
cd c:\dev\node\
call npx eslint  -f checkstyle c:\dev\node\sample.js > %WORKSPACE%\result.xml || type nul>nul
```

静的解析の警告が発生した場合eslintは1を返す。Jenkinsはバッチ実行中のコマンドが0以外を返すと中断されるため「|| type nul>nul」でエラーコードをクリアする。

２．２　ビルド後の処理を設定する
「ビルド後の処理」で「Record comppiler warnings and static analysis results」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/c8e3dc0b-48e5-78d4-f8a4-a5b5d712412b.png)

作成されたXMLをReport file patternに指定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/8108a10d-a30a-3d48-423f-5003cab61776.png)

３．ビルドを実行するとレポートが作成される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/a540ba62-5cb8-3daa-f02b-be8e0fbff79f.png)

<details>
<summary>**gjslintによる静的解析 (2014年時点の情報)**</summary>
<div>
gjslintは指定のコードが[Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml "Google JavaScript Style Guide")に違反していないか調べるツールである。

### gjslintのインストール方法
gjslintはPythonで動作するので、Pythonがインストールされていることが前提になる。

(1)easy_installを使用できるようにする。

```
wget http://peak.telecommunity.com/dist/ez_setup.py
python ez_setup.py
```

(2)gjslintをインストールする

```
easy_install http://closure-linter.googlecode.com/files/closure_linter-latest.tar.gz 
```

### gjslintの使用方法

使用例：

```
gjslint --disable 110,1 -r src
```

--disable コンマ区切りで無視するエラーを指定できる。
-r ディレクトリを再帰的に操作できる。

### closure-linter-wrapperによるXML出力
gslintのみでは検査結果をXMLとして保存することはできない。XMLとして出力できないと、jenkinsによる定期ビルドに組み込むことができない。
これを行うためにはclosure-linter-wrapperが必要である。
https://github.com/jmendiara/node-closure-linter-wrapper


(1)closure-linter-wrapperのインストール

```
npm install -g closure-linter-wrapper
```

(2)次のようなtest.jsファイルを作成する。

```
var argv = process.argv;
var gjslint = require('closure-linter-wrapper').gjslint;
var flagsArray = [
  '--nostrict',
  '--nojsdoc',
  '--disable 14'
];
console.log(argv[2] + 'src/*.js');

gjslint({
    src: [
      argv[2] + 'src/*.js'
    ],
    flags: flagsArray
    ,reporter: {
      name: 'gjslint_xml',
      dest: argv[2] + 'gjslint.xml'
    }
  },
  function (err, result) {
  }
);
```

この例では引数でしたフォルダのsrc以下を解析してgjslint.xmlに出力する。
あまりに大量のデータを一気にgjslint関数に渡すと正常にXMLが作成されないので注意すること。

### Jenkinsによるgjslintの集計
Jenkinsによりgjslintを定期的に実行し、その結果を集計することができる。

(1) jslintの結果を集計できるようにViolationsを入手する
Jenkinsの管理 > プラグインマネージャで利用可能タブから「Violations」を指定してインストールする。

(2) Jenkinsでシェルスクリプトを実行するようにして先に作成したclosure-linter-wrapperを使用するスクリプトを実行する

```
NODE_PATH=/usr/local/lib/node_modules
export NODE_PATH
node ${WORKSPACE}/test.js ${WORKSPACE}/
```

(3)ビルド後の処理のjslintに出力ファイルを指定しておく。
![b0232065_21404268.png](https://qiita-image-store.s3.amazonaws.com/0/47856/144c1967-04c8-8fd4-9de5-56105fe0043a.png)

(4)ビルドを行うと次のようなレポートが作成される。
![b0232065_21425396.png](https://qiita-image-store.s3.amazonaws.com/0/47856/2b23be68-9e61-32c4-ee6f-c6af0eed976d.png)

![b0232065_21430497.png](https://qiita-image-store.s3.amazonaws.com/0/47856/f8eff41e-d861-6ab2-7976-1fef6e3ef5d0.png)

</div>
</details>


## es6-platoによるコードメトリックスの収集
es6-platoを用いることで、ソースコードの行数や複雑度を計測できる。
https://github.com/the-simian/es6-plato


１．インストール方法

```
npm install --save-dev es6-plato
```

２．スクリプトから実行する

```
node_modules\.bin\es6-plato -r -d 出力フォルダ 解析対象のフォルダ
```

これにより出力フォルダ以下にHTMLが作成される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/69aff8bf-f82f-a6a4-62ea-89e64aae68f6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/f25bb41b-3d0a-d794-c75d-ae2c9a69953b.png)

Complexityが高いものがバグを発生しやすいので、テストケースの数や、リファクタリングの目安として監視する。
これもjenkinsで日々作成するといい。


# 単体テストの自動化
ここではnode.jsでのテストの自動化について記述する。ここではサーバーサイドの単体テストの自動化についてのみ記載するものとする。

単体テストを自動化する場合、以下の機能が必要になる。

 - テスト用フレームワーク
 - モック・フェイク
 - カバレッジの計測


## テスト用フレームワーク
Mochaは、Node.jsとブラウザーで実行される機能豊富なJavaScriptテストフレームワークであり、非同期テストをシンプルで楽しいものにします。

https://mochajs.org/

<font color="red">注意：2020年時点でjestにトレンド的に抜かれたようです</font>
https://www.npmtrends.com/jest-vs-jasmine-vs-mocha-vs-qunit-vs-ava-vs-chai-vs-expect.js-vs-should-vs-power-assert


### インストール方法
プロジェクトフォルダにインストールを行う。

```
npm install --save-dev mocha
```

### テストコードの記述例
testフォルダにテストコードを記載する。

```js
var assert = require('assert');
describe('sample', function () {
  it('syncOK', function () {
    assert.equal(2+2, 4);
  });
  it('syncNG', function () {
    assert.equal(2+2, 3);
  });
  it('asyncOK', function(done) {
    setTimeout(function() {
      assert.equal(2+2, 4);
      done();
    }, 15);
  });
  it('asyncNg', function(done) {
    setTimeout(function() {
      done('ng message');
    }, 15);
  });
});


```

### 実行例
下記のコマンドでtestフォルダ中のテストスクリプトを全て実行する。

```
npx mocha
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/2f862870-2ea3-8d3b-2778-c0b66681706a.png)



### Jenkinsとの連携方法
JUnit Reporter for Mochaを使用することでJUnitでのレポートを使用できる。
https://github.com/michaelleeallen/mocha-junit-reporter

```
npm install mocha-junit-reporter --save-dev
```

以下のコマンドを実行するとtest-result.xmlが作成される。

```
mocha --reporter mocha-junit-reporter
```

Windowsの場合は処理をとめないように以下のような処理を記載することになる。

```
cd c:\dev\node\
call npx mocha --reporter mocha-junit-reporter --reporter-options mochaFile=%WORKSPACE%\test_result.xml  || type nul>nul
```

ワークスペースにxmlを格納する場合は「--reporter-options mochaFile=ファイルパス」を利用する。

ビルド後の処理に「JUnitテスト結果の集計」を利用する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/4928b19f-74a5-1ee7-18a9-647023e82a0b.png)

テスト結果の集計は以下のように表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/93da451d-6ff0-30c5-65e7-807b49f290ad.png)


## モック・フェイク
モックやフェイクを使用することで依存している部品をテスト用に差し替えて実行することが可能になる。

このモックやフェイクの機能はSinon.jsでサポートされている。

**Sinon.js**
https://sinonjs.org/

インストール

```
npm install sinon --save-dev
```

モック対象の関数が以下の通り存在したとする。

```calc.js
"use strict";

module.exports = {
  add: ( num1, num2 ) => {
    return num1 + num2;
  }
};
```

この関数をsinonを使用して偽装した例は以下のとおり。

```js
var assert = require('assert');
var calc = require('../calc');
var sinon = require('sinon');

describe('test3.', function () {
  afterEach(() => {
    // Restore the default sandbox here
    sinon.restore();
  });

  it('stubの例.', function () {
    assert.equal(calc.add(1,3), 4);

    // スタブに置き換える
    sinon.stub(calc, 'add').callsFake(function(x,y) {
      console.log('stub function');
      return x*2 + y * 2;
    });
    assert.equal(calc.add(1,3), 8);

  });
});
```

### 時刻の偽装例
現在時刻を偽装する場合は[https://sinonjs.org/releases/v9.0.3/fake-timers/ sinon.useFakeTimers]を使用する。

現在時刻を1999/1/1 12:30:00(JST)にする場合

```js
  it('現在時刻の偽装の例', function () {
    sinon.useFakeTimers({
      now : new Date(1999, 0, 1, 12, 30, 00)
    });
    assert.equal((new Date()).getFullYear(), 1999);
    console.log(new Date());
  });
```

## カバレッジの計測
Istanbulを使用することで、カバレッジを取得することができます。

**Istanbul**
https://istanbul.js.org/


**インストール方法***
node.jsのプロジェクトにIstanbulをインストールするには下記のコマンドを実行する。

```
npm install --save-dev nyc
```

**実行例**
下記のコマンドでテストコードの実行と、カバレッジの計測が行える。

```
npx nyc mocha
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/81b4ae1e-e9c9-e87a-614b-75135328c486.png)

または以下のコマンドでhtml形式のレポートが作成可能

```
npx nyc --reporter=html mocha
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/e9e87c27-0f2c-58f8-37bf-b1f2f701e7d9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47856/483ed2c3-31a2-c3c3-9336-f90441c01140.png)