有一段代码我试图测试,
它是这样的:
class Foo {
//do some operations
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//some piece of code
}
}
}
那么我如何在运行函数中测试代码。我正在使用电源模拟,
线程在另一个类中启动,所以我不应该在那里调用它,对吗?
我仍然是一个初学者。
Runnable 的 run() 方法中的代码将在事件调度线程上调用。通常只应在此线程上执行 GUI 更新。使用模拟对象来测试 GUI 不是一个好主意。
取决于您要测试的内容。
如果要测试Foo
的行为,请不要担心并发性。只需拨打电话Foo
并断言获得的结果符合您的期望。只要org.junit.Assert
就足够了。
如果要测试此Runnable
的实际功能,则需要先中断依赖项。现在你的类Foo
依赖于一些Runnable
,这些在内部实例化和调用。将其转换为 Foo
的参数:
class Foo {
private Runnable runnable;
public Foo(Runnable rnbl) {
this.runnable = rnbl;
}
// somewhere later in the class
SwingUtilities.invokeLater(this.runnable);
}
现在你可以用 Mockito 和 test 来模拟这个 Runnable(在你的单元测试中):
Runnable mock = Mockito.mock(Runnable.class);
Foo foo = new Foo(mock);
foo.doSomething();
Mockito.verify(mock).run(); // verify that it was called
这就是将多线程应用程序转换为仅用于测试的单线程的方式。
据我了解,主要问题是异步。测试检查结果之前,我们将从 invokeLater() 块中获取结果。因此,我们需要等到 EDT 运行我们的代码并在检查之后。我们可以通过带有空可运行块的 invokeAndWait 方法来做到这一点。示例 Foo 类:
import javax.swing.SwingUtilities;
public class Foo {
private String myLine;
public void executeInEDT(final String line) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
myLine = line;
}
});
}
public String getLine() {
return myLine;
}
}
及测试方法:
@Test
public void testInvokeLater() throws InterruptedException, InvocationTargetException {
String testLine = "Test line";
Foo foo = new Foo();
foo.executeInEDT(testLine);
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
// Just for sync
}
});
assertEquals(testLine, foo.getLine());
// And more asserts
}
UPD:在 Netbeans 测试模式中找到了一些更多信息:
由于可运行的队列是 FIFO,因此可运行项调度在 在应用程序发布的所有任务之后结束,当它最终结束 执行一个可以确保应用程序的所有延迟任务在 AWT 事件队列也结束了。请参阅数据编辑器支持测试.java 有关应用程序代码需要等待的测试示例 完成发布到 AWT 事件线程的一些操作。