3

単体テストで EasyMock モックを挿入するように Spring を取得しようとしています。

私のapplicationContext.xmlには、これがあります:

<bean id="mockService"  class="org.easymock.EasyMock" factory-method="createMock"  name="MockService">
    <constructor-arg index="0" value="my.project.Service"/>
</bean>

私の単体テストでは、これがあります:

@Autowired
@Qualifier("mockService")
private Service service;

public void testGetFoo() {
    Foo foo = new Foo();

    expect(service.findFoo()).andReturn(foo);
    replay(service); // <-- This is line 45, which causes the exception

    // Assertions go here...
}

テストを実行しようとすると、次のスタック トレースが表示されます。

java.lang.ClassCastException: org.springframework.aop.framework.JdkDynamicAopProxy
at org.easymock.EasyMock.getControl(EasyMock.java:1330)
at org.easymock.EasyMock.replay(EasyMock.java:1279)
at TestFooBar.testGetFoo(TestVodServiceLocator.java:45)

私はSpringとEasyMockの両方にまったく慣れていませんが、EasyMockがEasyMockのインスタンスであると想定しているものでメソッドを呼び出そうとしたためにエラーが発生したようですが、実際にはSpringによって作成された動的プロキシです。私が理解しているように、動的プロキシはインターフェイスで定義されたメソッドのみを実装します。この場合は、サービスのインターフェイスです。

私が理解していないのは、私が読んだことここでも)から、少なくとも達成しようとしていることは可能であるように思われるということです。

私の質問は、私がしていないこと、または間違っていることは何ですか?

4

4 に答える 4

6

また、ヘルパー メソッドを作成して、Spring プロキシから EasyMock プロキシをアンラップし、期待される動作を定義することもできます。

public static <T> T unwrap(T proxiedInstance) {
  if (proxiedInstance instanceof Advised) {
    return unwrap((T) ((Advised) proxiedInstance).getTargetSource().getTarget());
  }

  return proxiedInstance;
}

最悪の場合、実際のターゲットに複数のプロキシがラップされているため、recusive 呼び出しに注意してください。

于 2009-06-02T13:05:36.040 に答える
4

解決しました!

私はapplicationContext.xmlでこれを見落としていました:

<bean id="txProxyAutoCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
        <list>

            <value>*Service</value>
            <!--   ^^^^^^^^    
               This is the problem!
            -->
        </list>
    </property>
    <property name="interceptorNames">
        <list>
            <value>txAdvisor</value>
        </list>
    </property>
</bean>

...これにより、Springは、名前が「Service」で終わるすべてのBeanのプロキシオブジェクトを自動的に作成します。

私の解決策は、ワイルドカードを使用する代わりに、Beanを明示的にリストすることでした。これは私には少しもろいように思えますが、FooServiceを除くすべての* Service Beanを指定する方法を誰かが知っているなら、私は感謝します。

于 2009-05-28T14:49:50.647 に答える
1

ここで何かがおかしい。Spring と EasyMock の両方をすぐにマスターしていることは明らかです。自動プロキシ、ファクトリ メソッド、すべて Spring の機能を深く掘り下げているという良い兆候です。

それでも、モック Bean をクラスに注入するのはちょっと奇妙です。あなたには大きな理由があるかもしれませんが、私にとってはコードの匂いです。実際のサービスをテスト クラスに接続し、必要に応じてモック オブジェクトを初期化することのみを検討することをお勧めします。依存関係のないモック オブジェクトを作成するために、Java で 3 行、XML でさらに 3 行 (およびそれらをリセットするために 1 行) を費やすのはなぜですか? Service service = (Service)createMock(Service.class) と言うだけです。必要なメソッドでそれらを作成し、期待を設定し、注入し、使用してから破棄することをお勧めします。モデルでは、使用するたびにモック オブジェクトをリセットすることを忘れないでください。これは、新しいオブジェクトを作成するよりも明確ではありません。

もちろん、これはスタイルの問題であり、正確さの問題ではないため、必要に応じて無視してください。

于 2009-05-29T15:30:27.930 に答える
1

この質問は古いことは知っていますが、同様の問題を探しているときに偶然見つけました。

問題は、Spring がモック オブジェクトの型を認識していないことです。使用する方法は次のようになります。

public static <T> T createMock(final Class<T> toMock) {
    return createControl().createMock(toMock);
}

Spring は、コンストラクターの引数から T を派生させるほどスマートではないため (少なくとも最後に確認したときは)、返されたオブジェクトの型は であると見なしますjava.lang.Object。結果として、作成されたプロキシは実装されmy.project.Serviceないため、注入できません。

したがって、答えは Spring に必要な型を伝えることです。

于 2014-04-29T11:47:45.937 に答える