ユニットテスト
StudentDay 10

テストしやすいようにメソッド分割するといい感じになったという話

More than 1 year has passed since last update.

この記事は、Student Advent Calendar 2016の第10日目の記事です。

メソッド分割の粒度はいつも迷うところですが、一つの目安として、テスト(単体テスト)が書きやすい粒度で分割すると、割りとスッキリと分割出来ました。


テストが書きやすいメソッドとは?

基本的には、何らかの値を与えたら1つの値を返すor1つに影響を与えるメソッドかつ、1つのことしか行わないメソッドです。

影響を与えるとは、DBへの書き込みや、APIへのPOSTなど、値は返さないが何らかの変更がなされることと考えてください。

値を返しつつ、DBへの書き込みもしたい(例えば、そのメソッドで算出した値をDBにログとして保存したいなど)場合は、DBへの書き込み部分を切り出してメソッド化し、そのメソッドを呼び出す形にしましょう。

1つのことしかしないとは、例えばそのメソッド内で何らかのWebAPIやDBを呼び出す必要があるとします。

取得した値をそのまま返すのであれば、1つのことといえますが、大体はデータの取捨選択やデータ構造を変更するかと思いますので、そのような場合はデータの取得と値の加工という2つのことをしています。


なぜそうするのか

ここまで分離するのめんどくさいと思う方も居るかと思います

ではここで例え話をしてみます。

DBのユーザー情報テーブルからユーザーidとユーザー名をとってきて、それぞれのキーの値を変更して呼び出し元に返すような動作のメソッドを作成しました

ところが、そのメソッドを呼び出すとNullが返ってきてしまいました。

もちろんバグなのですが、この場合、問題がDB部なのかDBから取ってきた値を変更する部分なのかの切り分け、すぐできますか?

もし分離していた場合、とりあえずDB部から値を取ってくるだけのメソッドを一度試しに呼んでみるとどちらのバグかすぐわかります(両方にバグが有るという可能性もありますが。)

メソッド数が少ないうちは有り難みがわかりづらいですが、メソッド数が増えてきてDB呼び出しやAPI呼び出しが増えてくると分離していないときに比べてとても楽になります。


Dependency Injection

メソッドを上のように分離すると、Dependency Injectionができるというメリットもあります。

特にTwitterAPIなんか顕著ですが、リクエスト制限数が厳しく、テストのたびに実際のAPIにリクエスト飛ばしてたらリクエスト数オーバーどころかBANされてもおかしくありません。

そこで、APIを呼び出しているメソッドだけをもう一つ作り、そこの中身は予め用意しておいたJSONを返すだけのメソッドを作ってしまえばAPIの制限なんか恐れずに何回でもテストできます。

実際に動かすときになっても変えるのはメソッドコール部分だけ。

わざわざコメントアウトを戻してテストコード部分をコメントアウトする・・・・なんて面倒なことは止めましょう。


最後に

メソッド分割は頭使いますし面倒ですが、肥大化した多数のメソッドからバグを探す。のような拷問のようなことに比べれば圧倒的に楽でしょう。

また、DBやAPIも呼び出し部と加工部に分離していれば、例えばMySQLじゃなくてPostgreSQLを使いたいときでもメソッドコール部分を変更するだけです。APIも回数制限気にせずテストし放題。

みなさんもどんどんメソッド分割してテストコード書いて開発を楽にしましょう。

結局のところ、単一責任の原則をしっかり守ろうってことです。