考虑以下代码:
public void actionPerformed(ActionEvent e) {
setEnabled(false);
new SwingWorker<File, Void>() {
private String location = url.getText();
@Override
protected File doInBackground() throws Exception {
File file = new File("out.txt");
Writer writer = null;
try {
writer = new FileWriter(file);
creator.write(location, writer);
} finally {
if (writer != null) {
writer.close();
}
}
return file;
}
@Override
protected void done() {
setEnabled(true);
try {
File file = get();
JOptionPane.showMessageDialog(FileInputFrame.this,
"File has been retrieved and saved to:\n"
+ file.getAbsolutePath());
Desktop.getDesktop().open(file);
} catch (InterruptedException ex) {
logger.log(Level.INFO, "Thread interupted, process aborting.", ex);
Thread.currentThread().interrupt();
} catch (ExecutionException ex) {
Throwable cause = ex.getCause() == null ? ex : ex.getCause();
logger.log(Level.SEVERE, "An exception occurred that was "
+ "not supposed to happen.", cause);
JOptionPane.showMessageDialog(FileInputFrame.this, "Error: "
+ cause.getClass().getSimpleName() + " "
+ cause.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
} catch (IOException ex) {
logger.log(Level.INFO, "Unable to open file for viewing.", ex);
}
}
}.execute();
url
是一个JTextField,而'creator'则是一个注入的接口用于写文件(因此这部分内容处于测试之下)。文件写入位置是故意硬编码的,因为它旨在作为示例。而java.util.logging仅被用来避免外部依赖。
你会如何划分块以使其可单元测试(包括放弃SwingWorker如果需要的话,但至少要替换这里使用的功能)?
我认为,doInBackground基本上是正确的。基本机制是创建一个写入器并关闭它,这几乎太简单了以至于不需要测试,真正的工作处于测试之下。然而,done方法有些问题,包括与父类中的actionPerformed方法的耦合以及协调按钮的启用和禁用。
然而,拆开这个方法并不明显。注入某种SwingWorkerFactory会使捕获GUI字段变得更加困难(很难看出它将如何成为设计改进)。JOptionPane和Desktop拥有所有“优点”的单例模式,并且异常处理使得很难轻松地封装get方法。
那么,有什么好的解决方案可以使这段代码可测试吗?
如何将代码划分为单元测试的块(包括放弃SwingWorker并替换其功能,至少在这里使用的方式)?doInBackground方法基本上正确。基本机制是创建一个写入器并关闭它,这几乎太简单了以至于不需要测试,真正的工作处于测试之下。但是,done方法有些问题,包括与父类中的actionPerformed方法的耦合以及协调按钮的启用和禁用。然而,拆开这个方法并不明显。注入某种SwingWorkerFactory会使捕获GUI字段变得更加困难,并且很难看出它将如何成为设计改进。JOptionPane和Desktop拥有所有“优点”的单例模式,并且异常处理使得很难轻松地封装get方法。因此,有什么好的解决方案可以使这段代码可测试吗?
SwingWorker
。通常情况下,将事物分解开来。当你有一个使用静态/单例的API时,引入一个接口,其中一个实现使用“真正”的静态API,另一个用于模拟(可能还有一个用于审计)。 - Tom Hawtin - tackline