【问题标题】:Mockito asks to add @PrepareForTest for the class even after adding @PrepareForTest即使在添加 @PrepareForTest 之后,Mockito 也会要求为该类添加 @PrepareForTest
【发布时间】:2016-10-21 20:34:41
【问题描述】:

我有以下简单的代码。我有一个类(TestClass),我想测试“someMethod”。我的“someMethod”调用了一个外部静态方法。 我想对该静态方法进行 Powermock 以返回一些虚拟对象。 我一开始就有@PrepareForTest(ExternalClass.class),但是当我执行它时会出现错误:

ExternalClass 类没有准备好进行测试。 要准备此类,请将 class 添加到 '@PrepareForTest' 注释。 如果您不使用此注解,请在类或方法级别添加注解。

请帮我指出我使用@PrepareForTest的方式有什么问题

@RunWith(PowerMockRunner.class)
@PrepareForTest(ExternalClass.class)
public class xyzTest {  
    @Mock
    private RestTemplate restTemplate;

    @Mock
    private TestClass testClass;

    @BeforeClass
    private void setUpBeforeClass() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testSuccessCase() {
        Boolean mockResponse = true;
        ResponseEntity<Boolean> response = new ResponseEntity<Boolean>(mockResponse, HttpStatus.OK);
        SomeClass someClass = new SomeClass("test", "1.0.0", "someUrl", "someMetaData");

        PowerMockito.mockStatic(ExternalClass.class);

        Mockito.when(restTemplate.postForEntity(any(String.class), any(String.class), eq(Boolean.class))).thenReturn(response);
        Mockito.when(ExternalClass.getSomeClass(any(String.class))).thenReturn(someClass);

        Boolean result = testClass.someMethod("test");

        Assert.isTrue(result);
        Mockito.verify(restTemplate, times(1)).postForObject(any(String.class), any(String.class), any());
    }
}

【问题讨论】:

  • 您是在桌面 JVM 中的 JUnit4 上运行此类,对吧?而ExternalClass不是一个Java系统类?
  • 是的,我在桌面 JVM(Oracle,1.8)上运行它。而 ExternalClass 是一个自定义的 Java 类(不是 Java 系统类:即 java*.*)
  • 我看到您正在使用 MockitoAnnotations.initMocks(...) 以及 Powermock JUnit Runner。这是不必要的。 Powermock 运行器将设置您的模拟。我不知道这是否会对您的情况有所帮助,因为我遇到了同样的问题,而且我没有再调用来初始化模拟。
  • 对我来说效果很好。您使用的是哪些 Mockito 和 Powermockito 版本?
  • 您绝对应该按照@Dan 的建议检查您的导入。但是您可能还会遇到由 @BeforeClass 注释应用于非静态方法 setUpBeforeClass 引起的初始化问题。

标签: java mockito powermock


【解决方案1】:

确保您也将@RunWith(PowerMockRunner.class) 添加到班级顶部。

::edit:: 两年后...

永远不要使用 PowerMockito,你不应该这样做。

如果您确实需要,您很可能违反了 SOLID 原则并且您的设计是错误的。

改正你的设计。

【讨论】:

  • 并将其委托给springrunner,以便您可以将其与spring boot集成; @PowerMockRunnerDelegate(SpringRunner.class)
  • 这个答案没有帮助。即使大多数时候您不应该模拟静态方法,但如果您不拥有该代码,则将静态方法转换为实例方法 (1) 可能是不可能的,并且 (2) 可能会使代码更容易出错。不模拟状态最可能的结果是不针对调用静态方法的代码编写测试。而且情况更糟。
  • 我非常同意@Vroo。我就在这种情况下,Apache 很高兴地违反了所谓的 SOLID 原则!在这件事上,我已经头疼了两天了。太糟糕了,这个答案已经成为 SO... 的热门话题......
  • 所以我们应该为我们使用的所有静态方法添加包装器?这没有任何意义,因为它们的存在是为了使用
  • @wild_nothing 所以为了在java中运行一个简单的函数而需要通过迂回的方式来实例化一个类?那么为什么标准的 java 类有静态方法呢?
【解决方案2】:

与上一个答案一样,我的问题也是混合来自 TestNG 的 Test 注释而不是 Junit Test。

import org.junit.Test; // works

import org.testng.annotations.Test // did not work

非常深奥的错误,我花了 5 多小时调试 :(

【讨论】:

    【解决方案3】:

    对于那些试图让它与 Junit 5 一起工作的人,如果您使用声称与 4+ 兼容的powermock-module-junit4 beta 版本,该库仍然无法识别:

    import org.junit.jupiter.api.Test;
    

    它会抛出一个:

    org.powermock.api.mockito.ClassNotPreparedException
    

    @PrepareForTest 应用于您要静态模拟的类时。如果你想使用 PowerMock,此时你将不得不回到 Junit 4 或者为你的静态方法创建一个 MockWrapper。

    PowerMock 2.0:Github Roadmap

    【讨论】:

      【解决方案4】:

      虽然这里评价最高的答案毫无疑问是正确的,但这并不能回答为什么需要这样的问题;或者,例如,为什么添加 @RunWith(MockitoJUnitRunner.class) 时同样的事情不起作用。

      问题是 PowerMockRunner 在后台使用检测 API,通过 javassist 库,这允许更改类,例如删除 final 或模拟 static(非编译时常量)。

      在修改(检测)某个类的过程中,他们为其添加了一个接口,称为PowerMockModified。它是一个标记接口,表示发生了某种字节码检测。稍后在代码中,他们只是通过这样的方法检查您在@PrepareForTest 中使用的类是否实际上以某种方式进行了检测:

          private boolean isModifiedByPowerMock() {
              return PowerMockModified.class.isAssignableFrom(this.type);
          }
      

      事实证明PowerMockRunner 做了一些检测,而MockitoJUnitRunner 没有;因此你得到的错误。

      【讨论】:

        【解决方案5】:

        我遇到了同样的错误,通过添加解决了这个问题

        @Rule
        public PowerMockRule rule = new PowerMockRule();
        

        在测试类中。

        【讨论】:

          【解决方案6】:

          如果上述答案不起作用,请尝试extends PowerMockTestCase。这个技巧对我有用。

          示例: public class xyzTest extends PowerMockTestCase

          【讨论】:

            【解决方案7】:

            检查是否导入 org.junit.Test;包已经导入,而不是那个 api jupiter one。

            【讨论】:

              【解决方案8】:

              我有同样的错误,但解决了。我的问题是我包含了powermock-module-junit4,但包含了来自TestNG而不是Junit的测试注释。

              【讨论】:

                【解决方案9】:

                我有同样的错误。我正在使用 TestNG 运行测试。我不得不使用以下方法来解决上述问题。

                @ObjectFactory
                    public IObjectFactory getObjectFactory() {
                        return new PowerMockObjectFactory();
                    }
                

                【讨论】:

                  【解决方案10】:

                  对于 testNG,有 2 个选项如下:

                  1. 使用 ObjectFactory 如下:
                      @ObjectFactory
                      public IObjectFactory getObjectFactory() {
                          return new PowerMockObjectFactory();
                      }
                  
                  1. 测试类扩展extends org.powermock.modules.testng.PowerMockTestCase

                  【讨论】:

                    【解决方案11】:

                    我的 gradle 使用的是 Junit 5。

                    test {
                        useJUnitPlatform()
                    }
                    

                    我能够调试这个。通过在 PowerMockRunner 方法中设置断点。 它没有被调用。此外,PowerMockito 不支持 JUnit 5。

                    看起来 JUnit5 在没有 @ExtendWith 的情况下运行。

                    【讨论】:

                      【解决方案12】:

                      确保您使用的是 powermock2。我在使用 powermock 时遇到了这个问题。 使用

                      import org.powermock2.api.mockito.PowerMockito;
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2017-02-09
                        • 2017-06-01
                        • 2018-11-25
                        • 2019-11-16
                        • 1970-01-01
                        • 2014-03-29
                        • 2015-05-18
                        • 2021-01-02
                        相关资源
                        最近更新 更多