【问题标题】:Mockito's spy does not work along with AspectJ using mavenMockito 的间谍不能与使用 maven 的 AspectJ 一起工作
【发布时间】:2015-05-30 20:41:03
【问题描述】:

我有以下测试类,并且正在使用 Mockito 的间谍。通过使用 Eclipse 运行我的单元测试(右键单击->作为单元测试运行),所有测试都通过了,这意味着使用 m2e 和 AJDT 的 eclipse 构建过程可以正常工作。

@RunWith(MockitoJUnitRunner.class)
public class SampleTest {

@Mock
private AnotherClazz mockedClazz;

@Spy
@InjectMocks
private SampleImpl sampleService = new SampleImpl() {

    @Override
    public void someMethod() {
       ...
    }
};


@Test
public void someTest() throws Exception {
    sampleService.methodUnderTest();
}

但是,当我使用 maven 运行测试时,出现以下异常。

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.183 sec <<<     FAILURE!
    org.sample.SampleTest  Time elapsed: 0.182 sec  <<< ERROR!
    org.mockito.exceptions.base.MockitoException: Problems initiating spied field     sampleService
    at     org.mockito.internal.runners.JUnit45AndHigherRunnerImpl$1.withBefores(JUnit45AndHigherRunnerImpl.java:27)
    at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:254)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class org.sample.SamplelTest$1
Mockito can only mock visible & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.
    ... 25 more
Caused by: org.mockito.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
    at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:238)
    at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
    at org.mockito.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
    at org.mockito.internal.creation.cglib.ClassImposterizer.createProxyClass(ClassImposterizer.java:123)
    at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:57)
    at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49)
    at org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24)
    at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33)
    at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59)
    at org.mockito.Mockito.mock(Mockito.java:1285)
    at org.mockito.internal.configuration.injection.SpyOnInjectedFieldsHandler.processInjection(SpyOnInjectedFieldsHandler.java:43)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.process(MockInjectionStrategy.java:68)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.relayProcessToNextStrategy(MockInjectionStrategy.java:89)
    at org.mockito.internal.configuration.injection.MockInjectionStrategy.process(MockInjectionStrategy.java:71)
    at org.mockito.internal.configuration.injection.MockInjection$OngoingMockInjection.apply(MockInjection.java:93)
    at org.mockito.internal.configuration.DefaultInjectionEngine.injectMocksOnFields(DefaultInjectionEngine.java:20)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.injectMocks(InjectingAnnotationEngine.java:100)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.processInjectMocks(InjectingAnnotationEngine.java:62)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:56)
    at org.mockito.MockitoAnnotations.initMocks(MockitoAnnotations.java:108)
    ... 25 more
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.mockito.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:385)
    at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:220)
    ... 44 more
Caused by: java.lang.VerifyError: Cannot inherit from final class
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    ... 50 more

在 Eclipse 中使用 AJC 编译器与 AJDT 和我的 AspectJ maven 插件配置之间有什么区别?我在这里缺少哪个配置或阶段?

这是我的 pom.xml:

<dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.6.11</version>
</dependency>
<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.4</version>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
            <executions>
                <execution>
                    <phase>process-sources</phase>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

更新:我还没有找到解决方案,但我知道为什么会这样。问题实际上在于覆盖 someMethod()。删除方法覆盖或注释掉 aspectj maven 插件可以解决问题作为解决方法。我不能让 AspectJ 退出我的项目,所以我必须在不覆盖它的情况下模拟 someMethod() (例如,使用 Mockito 本身)。对我来说它看起来像是一个错误,但我不太确定它是来自 AspectJ 还是 Mockito。

【问题讨论】:

  • SampleImpl 是最后一堂课吗?当您分配它的自定义实现时(通过声明 new SampleImpl() {...},但随后您要求 Mockito 也对此进行监视。然后 Mockito 尝试监视实际的 SampleImpl 类并抛出错误,因为该类是最终的。
  • 不,不是。它实际上是一个无状态的 EJB,不能是最终的,因为容器也使用 EJB 的代理模式,就像 Mockito 用于间谍一样,并且类不能是最终的。

标签: maven unit-testing mockito aspectj aspectj-maven-plugin


【解决方案1】:

在 Eclipse 中使用 AJC 编译器与 AJDT 和我的 AspectJ maven 插件配置有什么区别?

嗯,您在 Maven 中使用了 2011 年以来非常旧的 AspectJ 编译器和运行时,但您的 AJDT 可能使用的是更新的版本。顺便说一句,您的代码真的必须符合 Java 6 吗?无论如何,这应该不是问题,但我建议使用当前的 AspectJ Maven 插件 1.7 以及最新的 AspectJ 版本。你仍然可以用它编译 1.6 兼容的代码。当我尝试用旧的 AspectJ 版本重新创建您的情况时,代码甚至无法编译,但您没有提供真正的SSCCE,所以我不知道您的 JDK 版本、Mockito 版本、JUnit 版本等。

在你的 POM 中试试这个 Maven 配置:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.6</java.version>
    <aspectj.version>1.8.6</aspectj.version>
</properties>

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.3</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <!-- IMPORTANT -->
                <useIncrementalCompilation>false</useIncrementalCompilation>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.7</version>
            <configuration>
                <showWeaveInfo>true</showWeaveInfo>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <Xlint>ignore</Xlint>
                <complianceLevel>${java.version}</complianceLevel>
                <encoding>UTF-8</encoding>
                <verbose>true</verbose>
            </configuration>
            <executions>
                <execution>
                    <!-- IMPORTANT -->
                    <phase>process-sources</phase>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>1.9.5</version>
        <scope>test</scope>
    </dependency>
</dependencies>

这对我有用。顺便说一句,除了&lt;source&gt;&lt;target&gt;,请注意&lt;complianceLevel&gt;

【讨论】:

  • 嗨,亚历山大。感谢您的评论。升级到 AspectJ 插件 1.7 解决了这个问题。除了 maven 插件,我实际上使用的是 AspectJ 1.8.6 和所有最新版本的 Mockito (1.10.19) 和 JUnit (4.11)。现在我真的很想知道旧插件可能会导致什么样的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-26
  • 1970-01-01
相关资源
最近更新 更多