Edited at

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()
})
})
})