【问题标题】:Java, unit test mocking mxbeanJava,单元测试模拟 mxbean
【发布时间】:2016-06-08 11:52:11
【问题描述】:

我想按 CPU 时间对所有 Java 线程进行排序。我使用 ThreadMXBean 通过线程 ID 获取线程的 CPU 时间。比较器用于对 Thread ID 进行排序。

public class ThreadStats{
    private static ThreadMXBean mxbean = ManagementFactory.getThreadMXBean();

    class ThreadCPUCompare implements Comparator<Long>{

        @Override
        public int compare(Long threadId1, Long threadId2) {
            return Long.compare(mxbean.getThreadCpuTime(threadId2), mxbean.getThreadCpuTime(threadId1));
        }
    }
}

我做了以下单元测试:

@RunWith(MockitoJUnitRunner.class)
public class ThreadStatsTest {

@InjectMocks ThreadCPUCompare comperator = new ThreadStats().new ThreadCPUCompare();
@Mock ThreadMXBean mxbean;

@Test
public void threadCPUSortTest() {
    Mockito.when(mxbean.getThreadCpuTime(1L)).thenReturn(3L);
    Mockito.when(mxbean.getThreadCpuTime(2L)).thenReturn(2L);
    Mockito.when(mxbean.getThreadCpuTime(3L)).thenReturn(4L);
    Mockito.when(mxbean.getThreadCpuTime(4L)).thenReturn(1L);

    List<Long>expectedList = new ArrayList<Long>();
    expectedList.add(3L);
    expectedList.add(1L);
    expectedList.add(2L);
    expectedList.add(4L);

    List<Long>actualList = new ArrayList<Long>();
    actualList.add(4L);
    actualList.add(2L);
    actualList.add(3L);
    actualList.add(1L);


    //Sorting of the actual list
    Collections.sort(actualList, comperator);

    assertEquals(expectedList, actualList);
    }
}

但我无法进行测试。我认为是因为嘲笑不起作用。有人可以告诉我如何修复单元测试吗?

【问题讨论】:

  • 不确定,但您不需要调用verify(mxbean)吗?

标签: java unit-testing mocking mxbean


【解决方案1】:

您的测试失败,因为没有注入模拟。 Mockito 不会注入静态字段,也不会注入外部类(例如您的情况下的 ThreadStats 类)。

你需要这样写代码:

class ThreadCPUCompare implements Comparator<Long>
{
    private ThreadMXBean mxbean;

    @Override
    public int compare(Long threadId1, Long threadId2) {
        return Long.compare(mxbean.getThreadCpuTime(threadId2), mxbean.getThreadCpuTime(threadId1));
    }
}

@RunWith(MockitoJUnitRunner.class)
public class ThreadStatsTest
{
    @Mock ThreadMXBean mxbean;
    @InjectMocks Comparator comperator = new ThreadCPUCompare();

    @Test
    public void threadCPUSortTest() {
        // do your tests exactly as before
    }
}

然后您将面临将其连接到生产代码中的挑战,但这是一个不同的练习,我会推荐某种依赖注入(guice、spring、manual 等,具体取决于上下文和偏好)。

【讨论】:

  • 或者,让代码保持原样,编写测试,不要模拟。在这种情况下,测试可以简单地使用两个或三个线程,它们的 CPU 时间之间存在已知关系(例如,Thread.currentThread()new Thread())。嘲讽被高估了,最好避免,像这样的情况只会证实这一点。
  • @Rogério,你真的认为创建真正的线程并尝试控制它们的 cpu 时间会比模拟对 ThreadMXBean 的依赖项更优雅的解决方案吗?在这种情况下,请分享该解决方案。
  • 好的,我添加了我的答案。
【解决方案2】:

编写测试的一种简单方法如下,不涉及模拟:

public class ThreadStatsTest {
    Comparator<Long> comparator = new ThreadStats().new ThreadCPUCompare();

    @Test
    public void orderThreadIdsFromLongestToShortestCPUTime() {
        long longLivedThread = Thread.currentThread().getId(); // > 0 cpu time
        long shortLivedThread = new Thread().getId(); // 0 cpu time

        int longTimeFirst = comparator.compare(longLivedThread, shortLivedThread);
        int sameTimes = comparator.compare(longLivedThread, longLivedThread);
        int longTimeSecond = comparator.compare(shortLivedThread, longLivedThread);

        assertEquals(-1, longTimeFirst);
        assertEquals( 0, sameTimes);
        assertEquals( 1, longTimeSecond);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-22
    • 2011-04-11
    • 2020-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多