如何检测线程是否是使用 JUnit 生成的?

How can I detect if a thread was spawned using JUnit?

我正在使用 Java 6 和 Junit 4.12。我试图在 JUnit 中检测线程是否从 class 中生成。在我的 class 中,我像这样生成线程

final Thread deletethirdpartyClassThread = new Thread(new Runnable(){
    @Override
    public void run()
    {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            LOG.error(e.getMessage(), e);
        }
        final String threadName = "deletethirdpartyClass:" + myId;
        Thread.currentThread().setName(threadName);
        m_thirdpartySvc.deleteObject(myId);
    }
});
deletethirdpartyClassThread.start();

但是,在我的 JUnit 测试中,当我尝试获取 运行 个线程的列表时,上面的内容从未出现。这是我试图获取线程列表的方法

boolean threadSpawned = false;
final Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (final Thread t : threadSet) {
    if (StringUtils.equals(t.getName(), "deletethirdpartyClass:" + myId))
    {
        threadSpawned = true;
        break;
    }   // if
}   // for

是否有更好的方法来列出线程,或者是否有其他方法可以检测线程是否已生成?

看来你把这个复杂化了。只需让线程在启动时设置一个标志 运行 并让您的单元测试检查该标志以查看它是否曾经设置过。

例如,如果多个 "myId" 值是可能的:创建一个 public static HashMap(我称之为 s_threadFlags)用于映射一个"myId" 键到 Boolean 值,让 run() 方法将该映射中的 "myId" 值设置为 Boolean.TRUE,并让单元测试 class 获取该键的值。

线程代码可以是:

public static Map s_threadFlags;
public static void clearThreadFlags() { s_threadFlags = null; };
public static void initThreadFlags() { s_threadFlags = new HashMap(); };

final Thread deletethirdpartyClassThread = new Thread(new Runnable(){
    @Override
    public void run()
    {
        if (s_threadFlags != null) {
            s_threadFlags.put(myId, Boolean.TRUE);
        }
        m_thirdpartySvc.deleteObject(myId);
    }
});
deletethirdpartyClassThread.start();

单元测试代码可以简化为:

boolean threadSpawned = (MyThreadClass.s_threadFlags.get(myId) == Boolean.TRUE);

加上:

  • 在单元测试的 Before 或 BeforeClass 方法中调用 MyThreadClass.initThreadFlags()
  • 在 After 或 AfterClass 方法中调用 MyThreadClass.clearThreadFlags() 进行清理。

ThreadFactory 注入您的 class 并使用 创建新线程而不是调用 Thread::new。然后,JUnit 测试可以轻松地注入自定义 ThreadFactory 并验证是否要求创建新的 Thread.

private final ThreadFactory threadFactory;
private final Thread deletethirdpartyClassThread;

public YourClass(ThreadFactory threadFactory) {
    this.threadFactory = threadFactory;
    deletethirdpartyClassThread = threadFactory.newThread(new Runnable(){
        @Override
        public void run()
        {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                LOG.error(e.getMessage(), e);
            }
            final String threadName = "deletethirdpartyClass:" + myId;
            Thread.currentThread().setName(threadName);
            m_thirdpartySvc.deleteObject(myId);
        }
    });
}

和一个自定义滚动 ThreadFactory :

class MyThreadFactory implements ThreadFactory {

    private AtomicInteger invocationCounter = new AtomicInteger();

    @Override
    public Thread newThread(Runnable runnable) {
        invocationCounter.incrementAndGet();
        return new Thread(runnable);
    }

    public int numberOfInvocations() {
        return invocationCounter.get();
    }
}

如果您使用 Mockito,您可以简单地使用 spy()

在测试中你可以这样做:

public void test() {

    MyThreadFactory threadFactory = new MyThreadFactory();
    YourClass yourClass = new YourClass(threadFactory);

    yourClass. // invoke method under test

    assertThat(threadFactory.numberOfInvocations()).isEqualTo(1);

}