9

EasyMock を使用して、テストでオブジェクトをモックしています。しかし、コード内の別の場所で作成されたオブジェクトをモックするにはどうすればよいでしょうか? 次の疑似コードを見てください。WebService#getPersonById をモックしたいのですが、どうすればよいですか?

public class Person {
  public Person find(int id) {
    WebService ws = new WebService();
    return ws.getPersonById(id);
  }
}

public class PersonTest {
  testFind() {
    // How do I mock WebService#getPersonById here?
  }
}
4

5 に答える 5

9

通常、制御の反転と依存関係の挿入を使用してサービスを接続する場合、モッキングはうまく機能します。だからあなたの人は次のように見えるはずです

public class Person() {
  WebService ws = null;

  // or use setters instead of constructor injection
  Persion(WebService ws) {
     this.ws = ws;
  }
  public Person find(int id) {
    return ws.getPersonById(id);
  }
}

うまくいけば、この変更により、WebService のモックとモック コントロールを作成し、それをテストにプラグインすることができるようになったことは明らかです。これは、テストする Person を作成するときに、モックをコンストラクター (またはセッター) に渡すことができるためです。その道を行けば)。

実際の環境では、IoC コンテナーが実際の Web サービスを挿入します。

ここで、この IoC のすべてに対処したくない場合は、Web サービスを Person から分離する必要があります (エンティティを表す Person だけでなく、PersonService または何かを呼び出す必要があります)。つまり、コードの書き方では、1 種類の WebService しか使用できません。Personが、ハードコーディングした特定の WebService ではなく、ある種の WebServiceだけを必要とするようにする必要があります。

最後に、書かれているコードでは、WebService はインターフェイスではなくクラスです。WebService はインターフェイスである必要があり、何らかの実装を行う必要があります。EasyMock はインターフェイスでうまく機能します。具象クラスをモックできるかもしれませんが (実際に使用してからしばらく経ちました)、設計原則として、具象クラスではなく、必要なインターフェイスを指定する必要があります。

于 2011-01-26T16:51:07.597 に答える
3

EasyMock (または他のほとんどのモック API) でそれを行う方法はありません。一方、JMockit を使用すると、このようなテストは非常にシンプルでエレガントになります。

public class PersonTest
{
    @Test
    public testFind(@Mocked final WebService ws) {
        final int id = 123;

        new NonStrictExpectations() {{
            ws.getPersonById(id); result = new Person(id);
        }};

        Person personFound = new Person().find(id);

        assertEquals(id, personFound.getId());
    }
}

そのため、最初は単体テストを記述できない状況に遭遇した場合、テスト対象のコードがテスト不可能であり、リファクタリングが必要であると自動的に結論付けることはできません。場合によってはそうなる場合もありますが、常にそうであるとは限りません。問題はテスト対象のコードにあるのではなく、使用されている特定のモック ツールの制限にあるのかもしれません。

于 2011-02-14T13:27:58.523 に答える
1

もっと大きな問題を見落としていると思います。Personテストの難しさは、それ自体 (システムの一部) のさらなるインスタンスを見つけるためにリモート サービスも使用するオブジェクト (ドメインの一部) を持つことは、懸念事項を混同していることを伝えようとすることです。Personsの取得をPersonオブジェクトから切り離すと、よりクリーンで移植性の高いコードになります。

Person即時の利便性 (私は手にオブジェクトを持っているので、それを使用してより多くのオブジェクトを取得します) と保守容易性を混同しないでください。

于 2011-01-27T22:56:34.247 に答える
0

wsまず、通常は注入してモックを作成する必要があります。

public abstract class Person() {
  public Person find(int id) {
    WebService ws = createWebService();
    return ws.getPersonById(id);
  }
  protected abstract WebService createWebService();
}

次に、それを滑り込ませて、EasyMock.expect を使用してリターンをセットアップできます。

public class PersonTest() {
  testFind() {
    WebService mock = EasyMock.createMock(WebService.class);
    Person p = new Persion() {
      protected WebService createWebService() {
        return mock;
      }
    }
    EasyMock.expect(mock.getPersonById()).andReturn(dummyValue);
    //Test code
  }
}

PersonImplまた、実際の create メソッドを持つ必要があります。

于 2011-01-26T16:53:33.610 に答える
0

PowerMock whenNew メソッドを使用してみることができます

https://github.com/jayway/powermock/wiki/MockitoUsage#how-to-mock-construction-of-new-objects

その他の例はこちら - http://www.programcreek.com/java-api-examples/index.php?api=org.powermock.api.mockito.PowerMockito

あなたのコードは次のようになります -

whenNew(WebService.class).withAnyArguments().thenReturn(yourMockInstanceToWebServiceClass);

于 2016-05-07T03:09:23.837 に答える