如果抛出异常而不是显示失败,或者我是否应该在线程内部没有断言,我做错了什么?
@Test
public void testComplex() throws InterruptedException {
int loops = 10;
for (int i = 0; i < loops; i++) {
final int j = i;
new Thread() {
@Override
public void run() {
ApiProxy.setEnvironmentForCurrentThread(env);//ignore this
new CounterFactory().getCounter("test").increment();//ignore this too
int count2 = new CounterFactory().getCounter("test").getCount();//ignore
assertEquals(j, count2);//here be exceptions thrown. this is line 75
}
}.start();
}
Thread.sleep(5 * 1000);
assertEquals(loops, new CounterFactory().getCounter("test").getCount());
}
栈跟踪
Exception in thread "Thread-26" junit.framework.AssertionFailedError: expected:<5> but was:<6>
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.failNotEquals(Assert.java:277)
at junit.framework.Assert.assertEquals(Assert.java:64)
at junit.framework.Assert.assertEquals(Assert.java:195)
at junit.framework.Assert.assertEquals(Assert.java:201)
at com.bitdual.server.dao.ShardedCounterTest$3.run(ShardedCounterTest.java:77)
答案 0 :(得分:33)
JUnit框架仅捕获运行测试的主线程中的断言错误。它不知道新的生成线程中的异常。 为了做到正确,您应该将线程的终止状态传递给主线程。您应该正确地同步线程,并使用某种共享变量来指示嵌套线程的结果。
编辑:
这是一个可以提供帮助的通用解决方案:
class AsynchTester{
private Thread thread;
private AssertionError exc;
public AsynchTester(final Runnable runnable){
thread = new Thread(new Runnable(){
public void run(){
try{
runnable.run();
}catch(AssertionError e){
exc = e;
}
}
});
}
public void start(){
thread.start();
}
public void test() throws InterruptedException{
thread.join();
if (exc != null)
throw exc;
}
}
你应该在构造函数中传递runnable,然后你只需要调用start()来激活,然后调用test()来验证。如果需要,测试方法将等待,并将在主线程的上下文中抛出断言错误。
答案 1 :(得分:5)
Eyal Schneider's answer的小改进:
ExecutorService
允许提交Callable
,并且返回的Future
会重新抛出任何抛出的异常或错误。
因此,测试可以写成:
@Test
public void test() throws Exception {
ExecutorService es = Executors.newSingleThreadExecutor();
Future<?> future = es.submit(() -> {
testSomethingThatMightThrowAssertionErrors();
return null;
});
future.get(); // This will rethrow Exceptions and Errors as ExecutionException
}
答案 2 :(得分:4)
如果涉及多个工作线程,例如在原始问题中,仅仅加入其中一个是不够的。理想情况下,您需要等待所有工作线程完成,同时仍然将断言失败报告回主线程,例如在Eyal的答案中。
以下是使用ConcurrentUnit:
执行此操作的简单示例public class MyTest extends ConcurrentTestCase {
@Test
public void testComplex() throws Throwable {
int loops = 10;
for (int i = 0; i < loops; i++) {
new Thread(new Runnable() {
public void run() {
threadAssertEquals(1, 1);
resume();
}
}).start();
}
threadWait(100, loops); // Wait for 10 resume calls
}
}
答案 3 :(得分:0)
我最终使用了这个模式,它与Runnables和Threads一起使用。它很大程度上源自@Eyal Schneider的答案:
private final class ThreadUnderTestWrapper extends ThreadUnderTest {
private Exception ex;
@Override
public void run() {
try {
super.run();
} catch ( Exception ex ) {
this.ex = ex;
}
}
public Exception getException() throws InterruptedException {
super.join(); // use runner.join here if you use a runnable.
return ex;
}
}
答案 4 :(得分:0)
JUnit抛出Throwable扩展的AssertionError,它具有Exception的相同父级。您可以捕获线程的失败断言,然后保存在静态字段中,最后检查主线程是否另一个线程在某些断言中失败。
首先,创建静态字段
Test* t1 = new Test(0);
Test& t2 = *t1;
int i = t2.getData();
第二,将断言包装在try / catch中,并捕获AssertionError
t->getData()
最后,在主线程中检查该字段
private volatile static Throwable excepcionTE = null;