TypeORMのテストでFactoryを使って楽をする


はじめに

express.jsのコントローラー層のテストやTypeORMエンティティ(モデル)のテストを書く際、
毎回DBデータの作成に結構時間を取られたりしますが、Factoryメソッドを準備すれば
サクサクデータを作成してテストに集中することが出来ます。

注意
MySQLやPostgresqlのよなリレーショナルデータベース用の記事です。
MongoDB等には対応していません。

やりかた

自分でファクトリーの仕組みを作ってもいいのですが、typeorm-factoryという
便利なライブラリがあるため今回はそっちに全乗っかりします。
RailsのFactoryGirlFactoryBotのようなものです。

インストール


npm install --save-dev typeorm-factory

Factoryの作成

テストディレクトリ以下にhelperなり適当なディレクトリを作り、ファクトリーを作っていきます。
モデルが増えてきたら1モデル1ファイルに分割する等、お好みで管理していけばいいと思いますが
ここでは全モデル分1ファイルで定義します。
例として、Comment, Author, Postというエンティティを持っている場合

factory.ts

import { Factory } from 'typeorm-factory'
// エンティティ(モデル)のComment, Author, Postもインポートしておく

// .attr → 普通のカラムはこれで作ります
// .secuence → ユニーク成約等があるカラムの場合はindexを受取る無名関数を使って一意化出来ます
export const CommentFactory = new Factory(Comment)
  .sequence("text", (i) => `text ${i}`) 
  .attr("authorName", "John Doe"); 

export const AuthorFactory = new Factory(Author)
  .sequence("firstName", (i) => `John ${i}`)
  .sequence("lastName", (i) => `Doe ${i}`);

// .assocMany → toManyリレーション作成。最後の引数で一気に作る数を指定出来ます
// .assocOne → toOneリレーションを作成
export const PostFactory = new Factory(Post)
  .sequence("title", (i) => `title ${i}`)
  .sequence("text", (i) => `text ${i}`)
  .attr("likesCount", 10)
  .assocMany("comments", CommentFactory, 2)
  .assocOne("author", AuthorFactory);

使う

create()メソッドを使うとDBにもデータ作成、build()メソッドを使うとインスタンスのみ作成されます。
また、どちらのメソッドも好きなデータで上書きして作成することも出来ます。
一度に沢山作りたければcreateList() buildList() というものもあります。

コードには書いてませんが、DBコネクションがないとエラーになるため事前にコネクションを張って下さい。
jestならbeforeEachかbeforeAllで張ってafterEachかafterAllで閉じる感じでしょうか。


import { AuthorFactory, CommentFactory } from '../../helpers/factory'

describe('Post', () => {

  describe('someMethod', () => {
    it('なんたらかんたら', async () => {
      // DB作成
      const author1 = await AuthorFactory.create({firstName: "こうやって上書きできます"})
      // インスタンスのみ作成
      const author2 = await AuthorFactory.build()
      // リレーションも上書きできます。この場合はauthor1を親に持ったpostが作られます
      const post= await PostFactory.create({ author: author1 })
      // 一気に作る場合
      const posts= await PostFactory.createList({ author: author1 }, 10)

      // なんやかんやテストする
      // post.someMethod()
      // expect().toBe()
    })
  })
})