java jUnit如何在另一个线程中测试代码的结果
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5531608/
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
How to jUnit test the result of code in another thread
提问by IdahoEv
I have a process that runs in a thread (used as a realtime signal analysis process). I want to feed that thread process a known input, and then test -- in jUnit -- that the output is correct. I have a callback listener that can notify me when the thread finishes processing the data and I can run assertions on the result successfully by registering the test case itself as a listener.
When those assertions fail, they do throw an exception. But that exception is not registered as a failure by jUnit, presumably because they are happening outside of a test method.
我有一个在线程中运行的进程(用作实时信号分析进程)。我想为该线程提供一个已知的输入,然后在 jUnit 中测试输出是否正确。我有一个回调侦听器,它可以在线程完成数据处理时通知我,并且我可以通过将测试用例本身注册为侦听器来成功地对结果运行断言。
当这些断言失败时,它们会抛出异常。但是该异常并未被 jUnit 注册为失败,大概是因为它们发生在测试方法之外。
How do I structure my jUnit test so that the test fails correctly after the listener returns? Here's a simplified version of the code.
如何构建我的 jUnit 测试,以便在侦听器返回后测试正确失败?这是代码的简化版本。
public class PitchDetectionTest extends TestCase
implements EngineRunCompleteListener() {
AudioData fixtureData;
PitchDetectionEngine pitchEngine;
public void setUp() {
fixtureData = <stuff to load audio data>;
}
public void testCorrectPitch() {
pitchEngine = new PitchEngine(fixtureData);
pitchEngine.setCompletionListener(this);
pitchEngine.start();
// delay termination long enough for the engine to complete
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
}
// gets called by the PitchEngine when it has finished processing all data in the
// fixtureData. This is the only method defined by interface
// EngineRunCompleteListener.
public void notifyEngineRunComplete() {
// The real code asserts things about the PitchEngine's results. When they fail,
// an exception is thrown that I can see in the console, but this unit test still
// shows as 'success' in the jUnit interface. What I want is to see
// testCorrectPitch() fail.
assertTrue(false);
}
}
public class PitchEngine () {
EngineRunCompleteListener completionListener();
Thread myThread;
public void start() {
// other stuff
myThread = new Thread(this);
myThread.start();
}
public void run() {
while (some condition) {
// do stuff with the data
}
if (engineRunCompleteListener != null) {
engineRunCompleteListener.notifyEngineRunComplete();
}
}
}
采纳答案by Yoni
You already have two threads running. Your junit thread, and the process thread (started by myThread.start()
.
Off the top of my head, I can think of at least two options that you have, all of them involving moving the assertion away from notifyEngineRunComplete
. For example:
您已经有两个线程在运行。您的 junit 线程和进程线程(由myThread.start()
.开始,
在我的脑海中,我至少可以想到您拥有的两个选项,所有这些都涉及将断言从notifyEngineRunComplete
. 中移开。例如:
- You can use
join
to wait for the process thread to finish, and then do your assertions (Javadoc here). - You can put your junit thread to sleep by waiting on a monitor object, and then in your callback function notify this monitor. This way you'll know that the process has finished.
- You can use an
Executor
and aFuture
object. I think this would be the coolest solution if it works with your classes (Javadoc here).
回答by Jonathan
The general approach to testing threaded/async code is to block the main test thread, capture any failed assertions from other threads (such as the thread that calls your listener), unblock the main test thread and throw and failed assertion. ConcurrentUnitmakes this pretty straightforward:
测试线程/异步代码的一般方法是阻塞主测试线程,从其他线程(例如调用侦听器的线程)捕获任何失败的断言,解除主测试线程的阻塞并抛出和失败的断言。ConcurrentUnit使这非常简单:
final Waiter waiter = new Waiter();
bus.registerListener(() -> {
// Perform assertion in some other thread
waiter.assertTrue(true);
waiter.resume();
});
// Wait for resume() to be called
waiter.await(5000);
回答by matt b
I want to feed that thread process a known input, and then test -- in jUnit -- that the output is correct. I have a callback listener that can notify me when the thread finishes processing the data and I can run assertions on the result successfully by registering the test case itself as a listener.
我想为该线程提供一个已知的输入,然后在 jUnit 中测试输出是否正确。我有一个回调侦听器,它可以在线程完成数据处理时通知我,并且我可以通过将测试用例本身注册为侦听器来成功地对结果运行断言。
Rather than starting a separate thread for PitchEngine
inside your unit test, why not extract the //do stuff with the data
logic in PitchEngine
to another public method and simply invoke that in the unit test? I can't think of any reason to actually spawn the thread inside your unit test, since it sounds like all you really care about (in this unit test) is testing the processing logic.
与其PitchEngine
在单元测试内部启动一个单独的线程,为什么不将//do stuff with the data
逻辑提取PitchEngine
到另一个公共方法中并在单元测试中简单地调用它呢?我想不出有任何理由在单元测试中实际生成线程,因为听起来您真正关心的(在此单元测试中)是测试处理逻辑。
回答by jtahlborn
if you must run the assertion code within the callback, wrap the callback method in a try catch. catch any throwable and have a way of passing that exception back to the junit thread (some sort of shared thread state). the junit thread then just re-throws any returned throwable.
如果必须在回调中运行断言代码,请将回调方法包装在 try catch 中。捕获任何 throwable 并有办法将该异常传递回 junit 线程(某种共享线程状态)。然后junit 线程只是重新抛出任何返回的throwable。
回答by Jonathan
join()
works if you only have one worker thread that you want to perform assertions from. If you have multiple threads that need to report assertions back to the main thread, you'll need to use some other mechanism. Check out ConcurrentUnitfor that.
join()
如果您只有一个要从中执行断言的工作线程,则可以工作。如果您有多个线程需要向主线程报告断言,则需要使用其他一些机制。请查看ConcurrentUnit。