FullStackOpen Part4-a Structure of backend application, introduction to testing
Project Structure
Node.jsのベストプラクティスとしては以下のようなプロジェクト構造になる
├── index.js
├── app.js
├── build
│ └── ...
├── controllers
│ └── notes.js
├── models
│ └── note.js
├── package-lock.json
├── package.json
├── utils
│ ├── config.js
│ ├── logger.js
│ └── middleware.js
ロギング機能をあちこちに書くのはいい習慣ではないため、専用のモジュール(utils/logger.js)に割り当てる
infoとerrrorに分け、重大度別にする
const info = (...params) => {
console.log(...params)
}
const error = (...params) => {
console.error(...params)
}
module.exports = {
info, error
}
詳細は元のコースを参照
大きな変更点
loggerやconfigやエラーハンドラーなどのミドルウェアをutilフォルダに別モジュールとして分離
ルートハンドラー(notes.js)はcontrollerフォルダとして分けている
ルートハンドラーをモジュールとして取り扱うことで、テストしやすいなど様々なメリットがある
const notesRouter = require('express').Router()
//…
module.exports = notesRouternote.js(s無し)はモデル提供オンリーとして変更
app.jsとindex.jsを分離
app.js中でmongooseの接続を担当
その他ミドルウェアの使用、ルータの使用、エラーハンドラーの使用を実装index.jsはapp.jsをインポートしてサーバーをリッスンさせるだけ
Note on exports
exportsにエクスポートしたものには2通りの使い方がある
ドットでアクセス
const logger = require('./utils/logger')
logger.info('message')
logger.error('error message')Destructureして各関数に直接アクセス
const { info, error } = require('./utils/logger')
info('message')
error('error message')
Testing Node applications
アプリケーション開発の重要な要素であるテストについての話
jestを使う
npm install --save-dev jest
package.jsonに追加
{
//...
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"build:ui": "rm -rf build && cd ../frontend/ && npm run build && cp -r build ../backend",
"deploy": "fly deploy",
"deploy:full": "npm run build:ui && npm run deploy",
"logs:prod": "fly logs",
"lint": "eslint .",
"test": "jest --verbose"
},
//...
}
{
//...
"jest": {
"testEnvironment": "node"
}
}
テスト作成は以下のような構造で
テスト用ファイルは<function>.test.jsという拡張子で作成
test('test name', () => {expect(result).toBe('正しい値')}
const reverse = require('../utils/for_testing').reverse
test('reverse of a', () => {
const result = reverse('a')
expect(result).toBe('a')
})
test('reverse of react', () => {
const result = reverse('react')
expect(result).toBe('tcaer')
})
test('reverse of releveler', () => {
const result = reverse('releveler')
expect(result).toBe('releveler')
})
describe関数を使うとすっきりした形で書くことができる
const average = require('../utils/for_testing').average
describe('average', () => {
test('of one value is the value itself', () => {
expect(average([1])).toBe(1)
})
test('of many is calculated right', () => {
expect(average([1, 2, 3, 4, 5, 6])).toBe(3.5)
})
test('of empty array is zero', () => {
expect(average([])).toBe(0)
})
})