3

サービスの 1 つをテストしているときに、この奇妙な問題が発生します... easymock 3.0 で 2 つのサービスをモックし、Spring を注入していますが、いずれかで "java.lang.IllegalArgumentException: Not a mock: $Proxy43" 例外が発生します彼ら。次のように、構成ファイルで同じ方法で宣言しています。

<bean id="recurringSchedulesJobsService" class="org.easymock.EasyMock" factory-method="createMock">
    <constructor-arg value="com.spmsoftware.recurringschedules.service.RecurringSchedulesJobsService"/>
</bean>

<bean id="jobPeriodService" class="org.easymock.EasyMock" factory-method="createMock">
    <constructor-arg value="com.spmsoftware.jobdefinition.service.JobPeriodService"/>
</bean>

私のjunitテストでは、次の方法で使用しています:

@Autowired
private RecurringSchedulesJobsService recurringSchedulesJobsService;
@Autowired
private JobPeriodService jobPeriodService;

@Before
public void setUp() throws Exception {
    reset(recurringSchedulesJobsService);
    expect(recurringSchedulesJobsService.getBasedOnRecurringScheduleId(RECURRING_SCHEDULE_ID)).andReturn(buildRecurringScheduleJob());
    replay(recurringSchedulesJobsService);

    reset(jobPeriodService);
    expect(jobPeriodService.findPeriodByJobId(RECURRING_SCHEDULE_JOB_ID)).andReturn(buildJobDefinitionPeriod());
    replay(jobPeriodService);
}

recurringSchedulesJobsService が嘲笑され、2 番目のサービスにコメントすると、期待どおりに動作します。一方、jobPeriodService はモックとして認識されません。代わりに、次の例外が発生します。

java.lang.IllegalArgumentException: Not a mock: $Proxy43
at org.easymock.internal.ClassExtensionHelper.getControl(ClassExtensionHelper.java:66)
at org.easymock.EasyMock.getControl(EasyMock.java:2068)
at org.easymock.EasyMock.reset(EasyMock.java:1983)
at com.spmsoftware.recurringschedules.occurrences.generator.OccurrenceGeneratorTest.setUp(OccurrenceGeneratorTest.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)

ただし、例外は reset() メソッドでのみスローされます...

私が見つけた興味深い点の 1 つは、2 つのオブジェクトが同じインスタンスではないことです。これは、デバッグ時に得られるものです:

ここに画像の説明を入力

これに関するアイデアは非常に価値があります。ありがとう

4

2 に答える 2

5

Spring は、おそらく AOP の側面 (トランザクション、セキュリティ) をメソッドに適用するために、Bean をプロキシにラップします。したがって、テスト内に注入される Bean は、モック自体ではなく、モックの周りの Spring プロキシです。

しかし、なぜスプリング コンテキストと依存性注入を使用しているのですか? 単体テストでサービス オブジェクトをインスタンス化し、オブジェクトにモックの依存関係を挿入してテストするだけです。そのための Spring コンテナーは必要ありません。これはおそらく、IoC フレームワークの主な興味深い機能です。これにより、単体テストが簡単になります。

@Before
public void setUp() {
    this.recurringSchedulesJobsService = mock(RecurringSchedulesJobsService.class);
    this.jobPeriodService = mock(JobPeriodService.class);
}

@Test
public void testSomeMethod() {
    expect(recurringSchedulesJobsService.doThis()).andReturn(that);
    expect(jobPeriodService.doThat()).andReturn(1);

    replay(recurringSchedulesJobsService, jobPeriodService);

    MyServiceImplementation serviceToTest = 
        new MyServiceImplementation(recurringSchedulesJobsService, jobPeriodService);
    serviceToTest.someMethod();
    verify(recurringSchedulesJobsService, jobPeriodService);
}
于 2012-05-24T13:34:52.070 に答える
0

jobPeriodService は Spring によって自動プロキシされているようですが、recurringSchedulesJobsService はそうではありません。これはおそらく、Spring が recurringSchedulesJobService を自動プロキシの対象外としてマークしたためです (ポイントカットの一致の可能性がない、どこかで明示的にオフになっているなど)。他の構成を見ないと、具体的な理由が何であるかはわかりません。

Spring のロギング レベルを DEBUG に上げると、recurringSchedulesJobService が自動プロキシの対象にならない理由がわかります。

于 2012-05-24T16:05:03.357 に答える