如何undo/resetPowerMockito.mockStatic?

How to undo/reset PowerMockito.mockStatic?

假设我有以下 类

public class StaticClass {

    public static void staticMethod() throws SomeException {
        System.out.println("staticMethod");
    }

    private StaticClass() {
    }
}

public class SomeClass {

    public void someMethod() {
        try {
            StaticClass.staticMethod();
        }catch(SomeException ex) {
            System.out.println("SomeException occurred");
            return;
        }
        System.out.println("SomeException didn't occur");
    }
}

我正在测试

@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticClass.class)
public class SomeClassTest {

    @Test
    public void testStaticMethod() throws Exception {
        mockStatic(StaticClass.class);
        doThrow(new SomeException("unimportant message")).when(StaticClass.class,
                "staticMethod");
        //test something where exception is needed
        SomeClass instance = new SomeClass();
        try {
            instance.someMethod();
            fail("IllegalStateException expected");
        }catch(IllegalStateException expected) {
        }
        //now test something where exception isn't needed
        instance.someMethod();
    }
}

如何撤消静态 mocking/the 配置以抛出 SomeException 以便我可以在第二个 instance.someMethod() 中的 try-catch 块之后测试代码?

PowerMock: How to unmock a method? 不适用,因为没有模拟引用传递给 Mockito.reset 并且传递 StaticClass 会导致 java.lang.ClassCastException: java.lang.Class cannot be cast to org.mockito.internal.creation.bytebuddy.MockAccess.

SomeException 只是扩展了 Exception.

https://gitlab.com/krichter/powermock-undo-statik-mocking 提供了 SSCCE。

我正在使用 PowerMock 1.7.3。

我的意见,但一般来说,单元测试应该使用单一代码路径。 (我认为这是将单一职责应用于测试方法。)

Bu 我关于拆分测试的建议确实解决了问题。我不知道细节,但是@PrepareForTest 为每个测试.

提供了一个新的 StaticClass

这些单独的测试有效:

@Test
public void testStaticMethodWhenSomethingUnexpectedHappens() throws Exception {
    mockStatic(StaticClass.class);
    // changed exception type
    doThrow(new IllegalStateException("unimportant message")).when(StaticClass.class, "staticMethod");

    SomeClass instance = new SomeClass();
    try {
        instance.someMethod();
        fail("IllegalStateException expected");
    } catch (IllegalStateException expected) {
    }

    // added verification
    verifyStaticMethodWasInvokedOneTime();
}

@Test
public void testStaticMethodHappyPath() throws Exception {
    mockStatic(StaticClass.class);
    doNothing().when(StaticClass.class, "staticMethod");

    SomeClass instance = new SomeClass();
    instance.someMethod();

    // added verification
    verifyStaticMethodWasInvokedOneTime();
}

private void verifyStaticMethodWasInvokedOneTime() throws SomeException {
    verifyStatic(StaticClass.class);
    StaticClass.staticMethod();
}

任何想知道如何重置 PowerMocks 的人 e.x。对于那些讨厌的私人静态最终记录器...

有一个 issue(参见 Karl 在接受的解决方案中的评论)解决它,解决方案是在方法级别使用 @PrepareForTest。

所以在你的测试方法中你需要注释

/*
 * Test for MyClass.java which uses a private static final logger
 */
public class MyStaticMockTest {

  static final Logger logger = PowerMockito.mock(Logger.class);

  @BeforeClass
  public static void setup() {

    PowerMockito.mockStatic(LoggerFactory.class);
    PowerMockito.when(LoggerFactory.getLogger(MyClass.class))
        .thenReturn(MyStaticMockTest.logger);
  }


  @Test
  @PrepareForTest({LoggerFactory.class, Logger.class})
  public void testit() {
    MyClass mc = new MyClass();

    mc.methodWithSomeLogging();

    Mockito.verify(MyStaticMockTest.logger).info("some message");
  }

  @Test
  @PrepareForTest({LoggerFactory.class, Logger.class})
  public void testit() {
    MyClass mc = new MyClass();

    mc.anotherMethodWithSomeLoggingButUsingSameMessage();

    //Method will pass and not complain about info being called 2x
    Mockito.verify(MyStaticMockTest.logger, Mockito.times(1)).info("some message");
  }
}

如果您想要重置每个方法,只需将 @PrepareForTest 装饰器放在 class 而不是方法