2009-06-26 10 views
1

これは私が最近よく遭遇したパターンの例です。 私は、リストを取り、リスト内の各項目に対して他のメソッドを呼び出すメソッドをテストします。これをテストするためには、期待される呼び出しパラメータを持つIteratorを定義し、イテレータの各項目に対して呼び出しが行われているかどうかを確認するJMockの期待のループを作成します(下の簡単な例を参照してください)。リスト内の各項目の模擬メソッドの呼び出しをテストする方法がありますか

私はHamcrestのマッチャーを見てきましたが、これをテストする(または使用可能なマッチャーの仕組みを誤解している)ものは見つかりませんでした。誰かがよりエレガントなアプローチを持っていますか?

package com.hsbc.maven.versionupdater; 

import java.util.ArrayList; 
import java.util.Iterator; 
import java.util.List; 

import org.apache.maven.plugin.testing.AbstractMojoTestCase; 
import org.jmock.Expectations; 
import org.jmock.Mockery; 
import org.jmock.Sequence; 
import org.jmock.internal.NamedSequence; 

public class FooTest extends AbstractMojoTestCase { 

    public interface Bar { 
     void doIt(String arg); 
    } 

    public class Foo { 

     private Bar bar; 

     public void executeEven(final List<String> allParameters) { 
      for (int i = 0; i < allParameters.size(); i++) { 
       if (i % 2 == 0) { 
        bar.doIt(allParameters.get(i)); 
       } 
      } 
     } 

     public Bar getBar() { 
      return bar; 
     } 

     public void setBar(final Bar bar) { 
      this.bar = bar; 
     } 

    } 

    public void testExecuteEven() { 
     Mockery mockery = new Mockery(); 

     final Bar bar = mockery.mock(Bar.class); 
     final Sequence sequence = new NamedSequence("sequence"); 

     final List<String> allParameters = new ArrayList<String>(); 
     final List<String> expectedParameters = new ArrayList<String>(); 

     for (int i = 0; i < 3; i++) { 
      allParameters.add("param" + i); 
      if (i % 2 == 0) { 
      expectedParameters.add("param" + i); 
      } 
     } 

     final Iterator<String> iter = expectedParameters.iterator(); 

     mockery.checking(new Expectations() { 
      { 
       while (iter.hasNext()) { 
        one(bar).doIt(iter.next()); 
        inSequence(sequence); 
       } 
      } 
     }); 

     Foo subject = new Foo(); 
     subject.setBar(bar); 
     subject.executeEven(allParameters); 
     mockery.assertIsSatisfied(); 
    } 
} 

答えて

1

あなたの現在のテスト実装は理想に近いと思います。さらなる圧縮は、テストのセマンティクスを変更するか、テストの意図を読者(またはその両方)に不明瞭にする危険性があります。

あなたがメソッドの呼び出しの特定の番号を期待する方法を探している場合は、あなたがexactly(n).of()を使用することができます。

mockery.checking(new Expectations() {{ 
    exactly(expectedParameters.length()).of(bar).doIt(with(anyOf(expectedParameters))); 
}}); 

(私は均一性のチェックを残していますが、アイデアを得ます)。これは、別の答えのjmockitの例に似ています。これは、元のテストと同じことをテストしないことに注意してください。特に、それはチェックしません:

  1. doIt
  2. への呼び出しの順序をパラメータリストの各要素は、例えば、正確に一度

渡されたあなたの方法ならば、このテストに合格することを逆の順序でリスト全体を反復するか、またはdoItメソッドをn回だけ呼び出したが、毎回リストの最初の要素を渡した場合。リストの各要素が確実に渡されるようにするには、各要素の個別の期待値を設定して、繰り返し処理する必要があります。呼び出しの順序を気にしない場合は、シーケンスの使用を省略できます(その場合は、リストの代わりにコレクションを受け入れるために元のメソッドを変更することができます)。

1

おそらく次のようになります(jMo​​ckではなくJMockitを使用します)。


import java.util.*; 

import org.junit.*; 
import org.junit.runner.*; 

import org.hamcrest.*; 
import static org.hamcrest.core.AnyOf.*; 
import static org.hamcrest.core.Is.*; 
import org.hamcrest.core.*; 

import mockit.*; 
import mockit.integration.junit4.*; 

@RunWith(JMockit.class) 
public class FooTest 
{ 
    public interface Bar { void doIt(String arg); } 

    public class Foo 
    { 
     private Bar bar; 

     public void executeEven(final List<String> allParameters) 
     { 
     for (int i = 0; i < allParameters.size(); i++) { 
      if (i % 2 == 0) { 
       bar.doIt(allParameters.get(i)); 
      } 
     } 
     } 

     public void setBar(final Bar bar) { this.bar = bar; } 
    } 

    @Test 
    public void testExecuteEven(final Bar bar) 
    { 
     final List<String> allParameters = new ArrayList<String>(); 
     final List<Matcher<? extends String>> expectedParameters = 
     new ArrayList<Matcher<? extends String>>(); 

     for (int i = 0; i < 3; i++) { 
     allParameters.add("param" + i); 

     if (i % 2 == 0) { 
      expectedParameters.add(new IsEqual<String>("param" + i)); 
     } 
     } 

     new Expectations() 
     { 
     { 
      bar.doIt(with(anyOf(expectedParameters))); repeats(expectedParameters.size()); 
     } 
     }; 

     Foo subject = new Foo(); 
     subject.setBar(bar); 
     subject.executeEven(allParameters); 
    } 

    @Test // a shorter version of the same test 
    public void testExecuteEven2(final Bar bar) 
    { 
     final List<String> allParameters = Arrays.asList("param0", "param1", "param2"); 

     new Expectations() 
     { 
     { 
      bar.doIt(with(anyOf(is("param0"), is("param2")))); repeats(2); 
     } 
     }; 

     Foo subject = new Foo(); 
     subject.setBar(bar); 
     subject.executeEven(allParameters); 
    } 
} 
+0

ありがとう、これは確かに私が気づいていたもので、将来はそれを使用しますが、私はこのプロジェクトで使用できるテストフレームワークの選択肢が限られています。 –

+0

このバージョンは実際には同じことをテストしません。これは 'expected.Parameters.length()'が 'bar.doIt()'に呼び出され、各呼び出しが 'expectedParameters'の要素のうちの1つを渡すことだけを表明します。各要素が正確に1回だけ渡されるかどうかは検証されません。 コードがリストを反復処理できなかったというバグがある場合、このテストでは見つからないことがあります。 –

0

このテストを簡略化することができます。あなたが欲しいものを知っているので、あなたは、コードについてより具体的にすることができます

public void testExecuteEven() { 
    final List<String> values = Arrays.asList("param0", "param1", "param2", "param3"); 
    Sequence evens = mockery.sequence("evens"); 

    mockery.checking(new Expectations() {{ 
    oneOf(bar).doIt(values.get(0)); inSequence(evens); 
    oneOf(bar).doIt(values.get(2)); inSequence(evens); 
    }}); 

    subject.executeEven(values); 
} 

あなたはJUnitの4を使用している場合は、クラスの@RunWith(JMock.class)注釈が回避できることを忘れないでくださいassertIsSatisfied()呼び出しが必要です。

0

期待を一気に作成する必要はありません。あなたはループをchecking(new Expectations(){{}})ブロックの外に出すことができ、最終的にそれを嘲笑に渡す前に期待リストを操作することができます。これは、複雑な期待セットアップで明快を支援することができます(ので、コメントん!):また

@Test 
public void testExecuteEven() { 

    Mockery mockery = new Mockery(); 
    Sequence evens = mockery.sequence("evens"); 
    final Bar bar = mockery.mock(Bar.class); 

    List<Expectations> expectations = new ArrayList<Expectations>(); 

    final List<String> allParameters = new ArrayList<String>(); 
    final List<String> expectedParameters = new ArrayList<String>(); 


    // generate some parameters 
    for (int i = 0; i < 3; i++) { 
     allParameters.add("param" + i); 
     if (i % 2 == 0) { 
     expectedParameters.add("param" + i); 
     } 
    } 

    // define expectations for the expected parameters 
    for (String param : expectedParameters) { 
    expectations.add(new Expectations() {{ oneOf(bar).doIt(param); inSequence(evens); }}); 
    } 

    // define any special expectations here 
    expectations.add(new Expectations() {{ oneOf(bar).doSomethingElse() /* whatever */ }}); 

    // load the expectations into the mockery 
    for (Expectations expectation : expectations) { 
    mockery.checking(expectation); 
    } 

    Foo subject = new Foo(); 
    subject.setBar(bar); 
    subject.executeEven(allParameters); 

} 

、私はあなたは、Java 5のforeach文を使用していない注意してください。あなたがJava 4を使用して立ち往生していない場合でも、明快に役立つことがあります。

関連する問題