【问题标题】:How do I invoke a real function in my unit tests with jMockit?如何使用 jMockit 在单元测试中调用真实函数?
【发布时间】:2018-02-07 12:01:23
【问题描述】:

我已经阅读了这篇文章:Is there a way in JMockit to call the original method from a mocked method?

但推荐的解决方案会引发 NPE。这是我的来源

 static Map<String, Boolean> detectDeadlocks(int timeInSeconds) {
    final Map<String, Boolean> deadlockMap = new LinkedHashMap<>();
    new Timer().schedule(new TimerTask() {

      @Override
      public void run() {
        // I want to check if the method is run.
        **deadlockMap.put("deadlock", isDeadlockAfterPeriod());**
      }

    }, timeInSeconds * 1000);
    return deadlockMap;
  }

我希望能够在我的单元测试中调用isDeadlockAfterPeriod。这是我在单元测试中模拟的静态方法。

我的单元测试代码

  @Test
  public void testDetectDeadlocks() throws Exception {
    new Expectations(){
      {
           // Called from inside the TimerTask.
           ClassUnderTest.isDeadlockAfterPeriod();
           result = false;
      }
    };

    TimerMockUp tmu = new TimerMockUp();
    Deadlocks.detectDeadlocks(0);
    Assert.assertEquals(1, tmu.scheduleCount);
  }

  class TimerMockUp extends MockUp<Timer> {
    int scheduleCount = 0;

    @Mock
    public void $init() {}

    @Mock
    public void schedule(Invocation invocation, TimerTask task, long delay) {
      scheduleCount ++;
      invocation.proceed(); // Trying to call the real method, but this throws a NPE.
    }
  }

在 Eclipse 中使用 JUnit 可以看到错误堆栈跟踪。

java.lang.NullPointerException
    at com.myproject.test.DeadlocksTest$TimerMockUp.schedule(DeadlocksTest.java:78)
    at com.myproject.test.Deadlocks.detectDeadlocks(Deadlocks.java:41)
    at com.myproject.test.DeadlocksTest.testDetectDeadlocks(DeadlocksTest.java:86)

【问题讨论】:

  • 对于静态资源,可以使用PowerMock API来模拟。
  • 您能否添加 NPE 的堆栈跟踪以了解 null 的实际含义。
  • @PrathibhaChiranthana 我正在使用 jMockit 库。
  • @dpr 更新帖子。
  • 其实我觉得你方法的设计对测试不太友好。我将创建一个为TimerTask 创建Runnable 的方法。这样您就可以轻松地对Runnable 进行单元测试,而无需过多地模拟。

标签: java unit-testing jmockit


【解决方案1】:

您的问题是您还伪造了 Timer 的构造函数(不仅是 schedule 方法)。

这样做会阻止定时器的正确初始化,并且当您使用它的实际实现时,它会失败。

具体而言(使用我拥有的来源),您正在阻止其 queue 字段的初始化,该字段用于其 mainLoop() 方法(将调用您的 TimerTask.run() 的方法)。

此外,您需要对 Deadlocks 类进行部分模拟,据我了解,isDeadlockAfterPeriod 也是该类的静态方法。

我会给你一个工作示例:

Deadlocks.class

public class Deadlocks {

    public static Map<String, Boolean> detectDeadlocks(int timeInSeconds) {
        final Map<String, Boolean> deadlockMap = new LinkedHashMap<>();

        new Timer()// this will be the real constructor
                .schedule( // this will be first mocked, then really executed
                        new TimerTask() {

            @Override
            public void run() {
                deadlockMap.put("deadlock", isDeadlockAfterPeriod()); // this will put false after the mock is called
            }

        }, timeInSeconds * 1000);

        return deadlockMap;
    }

    public static Boolean isDeadlockAfterPeriod() {
        return true; // this, we will mock it
    }

}

测试类

@RunWith(JMockit.class)
public TestClass{
    @Test
    public void testDetectDeadlocks() throws Exception {
        new Expectations(Deadlocks.class){ // do partial mocking of the Deadlock class
            {
                // Called from inside the TimerTask.
                Deadlocks.isDeadlockAfterPeriod();
                result = false;
            }
        };

        // prepare the fake
        TimerMockUp tmu = new TimerMockUp();

        // execute the code
        Map<String, Boolean> result = Deadlocks.detectDeadlocks(0);

        // assert results
        assertThat(tmu.scheduleCount, is(1));
        assertThat(result.size(), is(1));
        assertThat(result.get("deadlock"), is(false));
    }

    class TimerMockUp extends MockUp<Timer> {
        int scheduleCount = 0;

        @Mock
        public void schedule(Invocation invocation, TimerTask task, long delay) {
            scheduleCount ++;

            invocation.proceed();
        }
    }
}

一般来说,伪造构造函数时要非常小心,因为您可能会使实例处于不一致的状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-19
    • 2021-06-16
    • 2021-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2015-12-25
    相关资源
    最近更新 更多