Como esse código do SwingWorker pode ser testado
Considere este código:
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
é um JTextField e 'creator' é uma interface injetada para gravar o arquivo (para que a parte esteja sob teste). O local em que o arquivo foi gravado é codificado de propósito, porque é um exemplo. E o java.util.logging é usado simplesmente para evitar uma dependência externa.
Como você classificaria isso para torná-lo testável por unidade (incluindo abandonar o SwingWorker, se necessário, mas depois substituir sua funcionalidade, pelo menos como usado aqui).
Na minha opinião, o doInBackground está basicamente bem. A mecânica fundamental é criar um escritor e fechá-lo, o que é muito simples de testar e o trabalho real está sendo testado. No entanto, o método done é problemático entre aspas, incluindo seu acoplamento com o método actionPerformed à classe pai e coordenando a ativação e desativação do botão.
No entanto, separar isso não é óbvio. A injeção de algum tipo de SwingWorkerFactory torna muito mais difícil a captura dos campos da GUI (é difícil ver como isso seria uma melhoria no design). O JOpitonPane e o Desktop têm toda a "bondade" dos Singletons, e o tratamento de exceções torna impossível envolver a obtenção facilmente.
Então, qual seria uma boa solução para colocar esse código em teste?