2014/01/31

JMockitまとめた。

チュートリアルをまとめてみた

2014/01/26

JUnitとJMockitのメモ

JUnit

  • assertThatでのアサーション失敗時に“NoSuchMethodError: org.hamcrest.Matcher.describeMismatch”が発生する
    • hamcrest関連の依存関係定義がJUnitより前になっていないと発生する場合がある
    • リンクを参照
      • Eclipseのビルドパスの順序を修正
      • Mavenの場合はpom.xmlのdependecyの順序を修正
        • ネストしたプロジェクトの場合、親プロジェクト側にJUnitの宣言がしてあったとしても、サブプロジェクト側で明示的にHamcrest、JUnitの順で明示的に宣言すると動く場合がある
  • SocketChannelなどをモック化したい。finalやstaticなメソッドをモック化したい
    • JMockitを使う

    JMockit

    Java用の最強モックツールキット。
    Mockito等に比べて、書き方が匿名メソッドと初期化フィールドというわかりにくいものだが、慣れてしまえばどうということはない。
    何よりfinalやstaticなクラスや、内部でnewしていてSetterがないフィールドをモック化したり、getterのないフィールドを取り出したり非常に便利。
    基本的な使い方はググれば出てくる。
    • ネストした呼び出しをモック化したい
      • @Cascadingを使う
        @Cascading SocketChannel channel;
        
        @Test
        public void testChannel() {
          new NonStrictExpectaions() {{
            channel.socket().getPort(); result = 1024;
          }}
          assertThat(channel.socket().getPort(), is(1024));
        }
        
        
    • インスタンスごとにモック化したい
      @Mockedで指定したフィールドは指定したフィールドだけでなく、スーパークラスも遡ってクラス単位でMock化されてしまう。
      • @Injectableを使う。
        • これに指定されたフィールドはテスト対象クラスに渡したりInjectすることを目的とされ、他のインスタンスやクラスに影響しない
      • パラメータとして渡す
        @Test
         public void test() {
           for (int i = 0; i < 10; i++) {
             final Dependency d = new Dependency();
             new NonStrictExpectations(d) {{ d.someMethod(); result = "foo"; }};
             list.add(d);
           }
         }
        
        
    • getterが無いフィールドを取り出したい
      • DeencapsulationクラスのstaticメソッドgetFieldを使う
      • リンク参照
    • モック化したはずなのに実行結果でnullが返る
      • Expectationsの中でいじったオブジェクトを、再度Expectationsの中で使ってしまうとおかしな挙動をする場合がある
        @Test
         public void test() {
           new NonStrictExcpectaions() {
             dep1.foo(); result = 1;
             dep2.bar(dep1.foo()); result = 2; // ←ここでdep1.foo()を呼ぶとおかしくなる
           }
           assertThat(dep1.foo(), is(1)); // ←NullPointerExceptionが発生する。
         }
          この場合dep2.bar(anyInt)のようにすると通る。
        
        
    • モック化したはずなのにメソッドが実行されない
      • 一部のメソッドはモック化できないらしい。
        • toString()
        • SocketChannel#close()
          • result = new IOException();とかやってもスルーされる。
      • 解決方法があれば教えてほしい。