如何检测线程是否是使用 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);
}
我正在使用 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);
}