Java 线程中的junit断言抛出异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2596493/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
junit assert in thread throws exception
提问by antony.trupe
What am I doing wrong that an exception is thrown instead of showing a failure, or should I not have assertions inside threads?
我做错了什么,抛出异常而不是显示失败,或者我不应该在线程内有断言?
@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());
}
StackTrace
堆栈跟踪
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.run(ShardedCounterTest.java:77)
采纳答案by Eyal Schneider
The JUnit framework captures only assertion errors in the main thread running the test. It is not aware of exceptions from within new spawn threads. In order to do it right, you should communicate the thread's termination state to the main thread. You should synchronize the threads correctly, and use some kind of shared variable to indicate the nested thread's outcome.
JUnit 框架仅捕获运行测试的主线程中的断言错误。它不知道新生成线程中的异常。为了正确地做到这一点,您应该将线程的终止状态传达给主线程。您应该正确同步线程,并使用某种共享变量来指示嵌套线程的结果。
EDIT:
编辑:
Here is a generic solution that can help:
这是一个可以提供帮助的通用解决方案:
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;
}
}
You should pass it the runnable in the constructor, and then you simply call start() to activate, and test() to validate. The test method will wait if necessary, and will throw the assertion error in the main thread's context.
您应该在构造函数中将 runnable 传递给它,然后您只需调用 start() 来激活,并调用 test() 来验证。如有必要,测试方法将等待,并将在主线程的上下文中抛出断言错误。
回答by Jonathan
Where multiple worker threads are concerned, such as in the original question, simply joining one of them is not sufficient. Ideally, you'll want to wait for all worker threads to complete while still reporting assertion failures back to the main thread, such as in Eyal's answer.
在涉及多个工作线程的情况下,例如在原始问题中,仅仅加入其中一个是不够的。理想情况下,您希望等待所有工作线程完成,同时仍将断言失败报告回主线程,例如在 Eyal 的回答中。
Here's a simple example of how to do this using ConcurrentUnit:
这是一个如何使用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
}
}
回答by Snicolas
I ended up using this pattern it work with both Runnables and Threads. It is largely inspired from the answer of @Eyal Schneider:
我最终使用了这种模式,它适用于 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;
}
}
回答by MyKey_
A small improvement to Eyal Schneider's answer:
The ExecutorService
allows to submit a Callable
and any thrown Exceptions or Errors are rethrown by the returned Future
.
Consequently, the test can be written as:
小改进的Eyal施奈德的回答:
在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
}
回答by Riki Gomez
JUnit throws AssertionError that extends of Throwable, it has the same parent of Exception. You can catch the fail assert of the thread, then save in a static field and finally check in the main thread if the other thread has failed some assert.
JUnit 抛出扩展 Throwable 的 AssertionError,它具有相同的 Exception 父级。您可以捕获线程的失败断言,然后保存在静态字段中,最后在主线程中检查其他线程是否失败了某些断言。
First, create the static field
一、创建静态字段
private volatile static Throwable excepcionTE = null;
Second, wrap the asserts in a try/catch and catch AssertionError
其次,将断言包装在 try/catch 中并捕获 AssertionError
try
{
assertTrue("", mensaje.contains("1234"));
}
catch (AssertionError e)
{
excepcionTE = e;
throw e;
}
And finally, check in the main thread that field
最后,在主线程中检查该字段
if (excepcionTE != null)
{
excepcionTE.printStackTrace();
fail("Se ha producido una excepcion en el servidor TE: "
+ excepcionTE.getMessage());
}