Node.js + Mongoose でテストデータを用意するなら Monky を使おう

こんにちは。Tokyo Otaku Mode エンジニアの bakorer こと重岡です。

「テスト書いてます?」

「いや、あんまり……」

「え? なんでテスト書かないの?」

「いや、だってスタートアップでリーンでアジャイルな開発サイクルを回していたら、モデルにガンガン変更入って……」

「そうだよなー。テストデータの準備って面倒だよな」

そんな You たちに朗報です。Mongoose でテストデータを用意する Monky ってライブラリがあるんです。しかも、無料。

というわけで今回は、Node.js + Mongoose という構成でテストデータの準備を楽にしてくれる Monky というライブラリを紹介します。

Monky とは?

Mongoose fixtures library inspired by factory_girl

つまり、Ruby on Rails 界隈で有名な FactoryGirl のインスパイア系で、テストデータの定義をまとめられるライブラリでございます。

超ベータ版で、2014/10/03 時点で Version 0.4.2 です。そして issue がひとつもないというアクティビティです。

しかも、Monky ってよく見ると Monkey ではなく Monky なんですよね。Monkey から e 抜いてるんですよね。ググらビリティ低いし、これだけじゃあ本当にいいことなしなんじゃないの? そんなことはありません(当然ですね)。

Monky を使うとなにがうれしいの?

ここからは、Monky を使うとなにがうれしいかを箇条書きで存分に語ります。

  • 決まったテストデータをテストコードにベタ書きしなくてよくなる
  • テストコードが増えてから field を追加する場合も一箇所に定義しているので修正量が少なくなる

以上!

早速、Monky を使ってみよう

ここまで読んで、Monky の魅力について存分に理解できたと思います。では、早速使ってみましょう。そうしましょう!

Sample Models

まず、下記のような典型的なモデルが定義されているとします。

  • Article
  • Comment
  • User

Article

1
2
3
4
5
6
7
8
9
10
11
Article = new Schema
title:
type: String
body:
type: String
user:
type: ObjectId
ref: "User"
Article.virtual("author_name").get ->
if @user?.name then @user.name else ''

Comment

1
2
3
4
5
6
7
8
9
Comment = new Schema
body:
type: String
article:
type: ObjectId
ref: "Article"
user:
type: ObjectId
ref: "User"

User

1
2
3
4
5
6
7
8
User = new Schema
username:
type: String
unique: true
full_name:
type: String
website:
type: String

Monky でテストデータを定義する

これらのモデル定義を前提に、Monky の Factory というテストデータの定義を登録します。
紙面の都合上、ArticleUser だけ書きました。

Article

1
2
3
4
5
6
7
8
mongoose = require 'mongoose'
Monky = require 'monky'
monky = new Monky mongoose
monky.factory 'Article',
title: '#n 番目のテスト記事'
body: '本文です'
user: monky.ref 'User'

User

1
2
3
4
5
6
7
8
mongoose = require 'mongoose'
Monky = require 'monky'
monky = new Monky mongoose
monky.factory 'User',
username: 'miku'
full_name: '初音ミク'
website: 'http://miku.example.com'

Build mongoose documents

定義した factory を使って、Article モデルのインスタンスを生成してみましょう。

やりたいことは、monky.build というメソッドを使えばできます。build はデータベースに保存していない Mongoose インスタンスを返すメソッドです。なので、monky.build 'Article', (error, article)-> で生成した article インスタンスに対して article.should.have.property 'isNew', true というテストが必ず通ります。

また、factory で定義した property を上書きしたい場合は、 monky.build 'Article', { title : 'スッペシャル記事' }, (e, a)-> というふうに第2引数に指定してあげればいいのです。

Create mongoose documents

インスタンスの生成だけでなく、保存までされた状態で欲しいという場合には monky.create メソッドを使います。

使い方は、monky.build と同じで monky.create 'Article', (error, article)-> と呼べば、保存済みの article インスタンスを返してくれます。

また、Mongoose schema に validation を定義していたら、このタイミングでエラーが発生します。

Defining named factories

テストデータの定義にわかりやすい名前を付けたいというニーズは必ずあるでしょう。ユーザひとつ取っても、ゲストユーザ、一般ユーザ、Admin ユーザなど、同じモデルでも名前付けできる……。

例えば、Admin ユーザの定義を追加してみたのが下記です。

1
2
3
4
5
6
7
8
monky.factory
name: 'Admin'
model: 'User'
,
username: 'admin'
full_name: '管理者'
website: 'http://admin.example.com'
admin_flag: true

monky.factory の第1引数に name: 'Admin' というように factory の名前と、利用するモデルを model: 'User' と指定するだけで、あとは同じです。

そして、使うときは name で指定した名前で monky.create 'Admin', (error, adminUser)-> というように呼び出してください。

monky.ref を使って関連もカンタンに再現する

Monky には monky.ref という field に指定した document も一緒に生成してくれる機能があります。しかも、populate された状態なので、ref 先のモデルの property を利用した virtual 用のテストデータもカンタンに用意することができるのです。

monky.ref を使って Article モデルに定義した auther_name virtual のテストを書いたものが下記です。

1
2
3
4
5
6
7
8
9
10
11
mongoose = require 'mongoose'
should = require 'should'
describe "Article", ->
it "should have a populated user", (done) ->
monky.create "article", (e, article) ->
article.user.should.be.an.instanceof mongoose.Document
article.user.name.should.eql 'miku'
article.auther_name.should.eql 'miku'
do done

article.auther_name.should.eql 'miku' のテストケースが通るので、article が create されるのと同時に ref の先の user も生成されていることがわかります。

まとめ

Node.js + Mongoose の構成でテストを書くなら、Monky を使うとテストコードを短く書けていいんじゃないでしょうか。define, ref ぐらいはすっきり定義できます。ただし、FactoryGirl にある after_create, attributes_for, stub など便利メソッドが未実装なので、issue 作成するか Contribute していきたいですね。

最後に、Tokyo Otaku Mode はテストカバレッジも売上も右肩上がりにしてくれるエンジニアを募集中です。ご興味がありましたら、こちらからご応募ください。

参考資料

本記事は先日、社内で開催した「東京OtakuMode学園#1」というエンジニア、デザイナー向けイベントで発表した資料を元に書いています。