Considerate questo codice:Come può questo codice SwingWorker essere testabile
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
è un JTextField e 'creatore' è un'interfaccia iniettato per la scrittura del file (in modo che una parte è in fase di test). La posizione in cui il file è scritto è hardcoded di proposito perché questo è inteso come un esempio. E java.util.logging è usato semplicemente per evitare una dipendenza esterna.
Come si spende questo per renderlo unit-testabile (incluso l'abbandono di SwingWorker se necessario, ma poi la sua sostituzione, almeno come usato qui).
Il modo in cui lo guardo, il doInBackground è fondamentalmente ok. I meccanismi fondamentali stanno creando uno scrittore e chiudendolo, il che è quasi troppo semplice da testare e il vero lavoro è sotto test. Tuttavia, il metodo done è problematico, incluso il suo accoppiamento con il metodo actionPerformed della classe genitore e il coordinamento dell'abilitazione e disabilitazione del pulsante.
Tuttavia, separare ciò non è ovvio. L'iniezione di una specie di SwingWorkerFactory rende molto più difficile la cattura dei campi della GUI (è difficile vedere come sarebbe un miglioramento del design). Il JOpitonPane e il Desktop hanno tutta la "bontà" di Singletons, e la gestione delle eccezioni rende impossibile avvolgere l'ottenere facilmente.
Quindi quale sarebbe una buona soluzione per portare questo codice sotto test?
codice riformattato; per favore, ripristina se non è corretto. – trashgod
Non una risposta completa: ma se ti piace il codice di qualità, non avvicinarti a 'SwingWorker'. In generale, fatelo fuori. Dove hai un'API che usa statica/singletons presenta un'interfaccia con un'implementazione usando l'API statica "reale" e un'altra per il mocking (possibilmente un'altra per l'auditing). –
@Tom, se hai tempo per scrivere la bozza di un disegno alternativo a SwingWorker (o se conosci una migliore implementazione alternativa) sarebbe molto apprezzato. – Yishai