モッククラスにおける匿名クラスの利用

最近の開発者は匿名クラスを知らない」のエントリで,以下のように書いた。

単体テストのコードを書く際には,匿名クラスを使ったテクニックが非常に有効だったりする

特にモッククラスを作るときに,僕は匿名クラスを良く使う。 最近のSSH(Struts+SpringFramework+Hibernate)などでは,3層構造(Web+Service+Dao)における中間のService層の単体テストに関して,Daoのモックを作る機会が多い。Daoのインタフェースに多くのメソッドが搭載されている場合,何も考えずにモッククラスを作ってしまうと,「return null;」といったコードが盛り沢山になってしまう。 そんな場合は,EasyMockなどを使ってモッククラスの自作を避ければ解決なのだが,諸事情(?)によりEasyMockなどのライブラリをチームに展開することが困難なこともある。その場合,モッククラスは全て手書きする必要がある。 あるServiceの実装クラス内では,使用しているDaoの中で呼び出しているメソッドが特定のものに集中していることも多い。1つや2つのDaoのメソッドについて,正しい呼び出しが行われたかどうかを各テストメソッドで行おうとした場合,テストメソッド毎に固有のモッククラスを内部クラスとして作成するとなると,かなりの記述量になってしまう。それに,モッククラス内に渡された情報に対する妥当性検証処理(ようはassertEquals)が内部クラスに書かれることになると,テストメソッドから遠い場所に記述することになってしまう。単体テストのコードは,見通しの良さが絶対条件。 そこで,匿名クラスの登場となる。

class HogeTest extends TestCase {  private HogeService target;  …  public void testGetHogeModel() throws Exception {    final int id = 10;    HogeModel expected = …;    HogeDao mock = new AbstractHogeDaoMock() {      public HogeModel getHogeModel(int a) {        assertEquals(“id”, id, a);        return expected;      }    };    target.setHogeDao(mock);    HogeModel result = target.getHogeModel(id);    …  }  private abstract class AbstractHogeDaoMock implements HogeDao {    public void updateHogeModel(…) {fail();};    public HogeModel find1(…) {fail();return null;};    public HogeModel find2(…) {fail();return null;};    public HogeModel find3(…) {fail();return null;};    public HogeModel find4(…) {fail();return null;};    …  }}

モッククラスを抽象クラスとして作成し,テストメソッドから使われるメソッド以外のメソッドを実装している。抽象クラスに実装したメソッドは,このテストケースの対象オブジェクト(HogeServiceの実装)からは使われないものである。よって,これらのメソッドが呼び出されたということは想定外なので,fail()で失敗するようにしている。 各テストメソッドでは,モックオブジェクトを匿名クラスとして定義し,生成と同時にメソッドの実装を行っている。上記のようにすることで,テストメソッドに特化した実装をモックオブジェクトに施すことができ,しかもモックオブジェクトに持たせる検証処理がテストメソッド内に記述されるようになるために,見通しが良くなっている。しかも,テストメソッド毎に内部クラスをいちいち作成する必要もないので,省エネ(=品質向上)にもなる。 匿名クラスは,知ってるのと知らないのでは,コードの美しさや効率さに差が大きく出る。最近の開発者の方々も是非身につけておいて欲しい。

このエントリーをはてなブックマークに追加

関連記事

2023年のRemap

Remapにファームウェアビルド機能を追加しました

Google I/O 2023でのウェブ関連のトピック

2022年を振り返って

現在のRemapと今後のRemapについて