线程中的junit断言抛出异常
我做错了什么,抛出异常而不是显示失败,或者我不应该在线程内有断言吗?
@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)
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$3.run(ShardedCounterTest.java:77)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
JUnit 框架仅捕获运行测试的主线程中的断言错误。它不知道新生成线程内的异常。
为了正确执行此操作,您应该将线程的终止状态传达给主线程。您应该正确同步线程,并使用某种共享变量来指示嵌套线程的结果。
编辑:
这是一个可以提供帮助的通用解决方案:
您应该在构造函数中将可运行对象传递给它,然后只需调用 start() 来激活,并调用 test() 来验证。如果需要,测试方法将等待,并在主线程的上下文中抛出断言错误。
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.
EDIT:
Here is a generic solution that can help:
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.
对Eyal Schneider 的答案的一个小改进:
ExecutorService
允许提交一个Callable
,任何抛出的异常或错误都会被返回的Future
重新抛出。因此,测试可以写成:
A small improvement to Eyal Schneider's answer:
The
ExecutorService
allows to submit aCallable
and any thrown Exceptions or Errors are rethrown by the returnedFuture
.Consequently, the test can be written as:
当涉及多个工作线程时,例如在最初的问题中,仅加入其中一个是不够的。理想情况下,您需要等待所有工作线程完成,同时仍将断言失败报告回主线程,例如 Eyal 的回答。
以下是如何使用我的 ConcurrentUnit 执行此操作的简单示例:
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.
Here's a simple example of how to do this using my ConcurrentUnit:
JUnit 抛出继承于 Throwable 的 AssertionError,它与 Exception 具有相同的父级。您可以捕获线程的失败断言,然后保存在静态字段中,最后在主线程中检查其他线程是否使某些断言失败。
首先,创建静态字段
其次,将断言包装在 try/catch 中并捕获 AssertionError
最后,在主线程中检查该字段
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.
First, create the static field
Second, wrap the asserts in a try/catch and catch AssertionError
And finally, check in the main thread that field
我最终使用了这种模式,它适用于可运行对象和线程。它很大程度上受到@Eyal Schneider 的回答的启发:
I ended up using this pattern it work with both Runnables and Threads. It is largely inspired from the answer of @Eyal Schneider:
我一直在寻找一个简单且可读的解决方案。受到 Eyal Schneider 和 Riki Gomez 答案的启发,我得出了这样的结论:
因此,您可以借助
static
变量实现所需的结果。线程照常运行,您所要做的就是将您感兴趣的异常存储在static
变量上。只是不要忘记在每次测试之前将其值重置为 null,否则您可能会在同一类的后续测试中遇到麻烦。最后说明:如果您计划在同一个测试中运行多个线程,并且预计它们同时运行相同的代码块,我建议将
static 变量
易失性
以便变量的更新可预测地传播到其他线程:I was looking for a simple and readable solution. Inspired by Eyal Schneider and Riki Gomez's answer, I've come up with this:
So, you can achieve the desired result with the help of a
static
variable. The thread runs as usual, and all you have to do is store the exception you are interested in on thestatic
variable. Just don't forget to reset its value tonull
before every test, or you may run into trouble on subsequent tests on the same Class.Final note: If you are planning on running multiple Threads on the same test, and it is expected for them to run the same blocks of code simultaneously, I would advice to make the
static
variablevolatile
so that updates to the variable propagate predictably to other threads: