2015-07-29 11 views
6

Ho bisogno di testare una classe per determinare se un'azione pertinente ha avuto luogo dato un determinato input. Il codice più o meno così:Come testare unitamente un metodo di annullamento senza argomenti

protected static void receiveInput() { 
    String command; 
    boolean b = true; 
    Scanner scanner = new Scanner(System.in); 

    while (b) { 

     command = scanner.next(); 
     switch(command) { 

      case "first": 
       System.out.println("First!"); 
       break; 

      case "second": 
       System.out.println("Second!"); 
       break; 

      case "third": 
       System.out.println("Third!"); 
       break; 

      default: 
       System.out.println("\n***** Invalid *****\n"); 
     } 

     System.out.println("\n"); 
    } 

    scanner.close(); 
} 

posso probabilmente ottenere una prova di unità abbastanza approfondita se posso in qualche modo controllare la stringa di comando e tenere traccia dell'oggetto scanner. Per qualche ragione, in realtà non mi è permesso iniettare questi due oggetti come argomenti per questo metodo. Quali opzioni ci sono per fare questo test in un modo diverso?

+2

Non è possibile impostare una funzione di ritorno valore di tipo 'stringa' e restituire semplicemente la stringa del caso specifico da verificare? – Adam

+2

Sei in grado di cambiare questo metodo per renderlo più facile da testare unitamente? –

+0

Questo non è un metodo molto semplice per test di unità. Di solito per me, quando collaudo i metodi void, è perché producono una sorta di effetto collaterale o cambiamento di stato. Quindi testerò se quell'effetto collaterale si è verificato correttamente.Sfortunatamente, in questo caso sarà abbastanza difficile testare l'unità senza cambiare il metodo. – JNYRanger

risposta

1

Oltre all'ottima risposta di MattPutnam, esistono due suggerimenti specifici per il metodo.

1.Cambia di tornare stringhe

protected static string receiveInput(String arg) { 
    String result; 
    String command = arg; 
    boolean b = true; 

    while (b) { 
     switch(command) { 

      case "first": 
       result = "first"; 
       break; 

      case "second": 
       result = "second"; 
       break; 

      case "third": 
       result = "third"; 
       break; 

      default: 
       result = "\n ****Invalid*** \n"; 
     } 
    } 
    return result; 
} 

2.My preferenza sarebbe solo per testare se boolean b è vero o no. Se è vero, sai che ha funzionato, in caso contrario, non è così. Modifica: Si noti che questo potrebbe essere pericoloso poiché non si verificherà che lo standard arg soddisfi necessariamente i criteri della stringa, ma che abbia una risposta accettabile.

Circa l'unico modo per testare questo metodo corrente è in qualche modo catturare lo stream come risposta MattPutnam nei commenti.

+1

pericoloso solo per dimostrare il booleano ... e suggerirei di estrarre l'intera logica in un proprio metodo come diceva MattPutman ... – Anton

+0

Ecco perché l'avevo elencato dopo il numero 1. Capisco perché dici che potrebbe essere pericoloso ora che ho letto la mia risposta. Io modifico – Adam

+0

@MilesPeterson, suggerisco caldamente di accettare la risposta di MattPutnam – Adam

15

Questo è un esempio perfetto per rendere più controllabili le funzioni. Questa funzione non accetta input e non produce output, influenzando il mondo solo tramite effetto collaterale, rendendolo completamente non verificabile attraverso mezzi standard.

di refactoring questa funzione per renderlo più verificabili:

  • Non chiedere all'utente per l'input tramite scanner, prendere l'input dell'utente come parametro di input.
  • Non stampare il risultato, restituirlo.

Il chiamante della funzione può quindi decidere come fornire gli input e cosa fare con l'uscita. Il tuo programma modificato può chiedere l'input dell'utente, chiamare la funzione, quindi stampare l'output. Un framework di test può fornire l'input da un elenco di input da testare e controllare le uscite rispetto ai valori previsti.

+1

È possibile racchiudere la "business logic" in un metodo testabile che prende l'input e restituisce l'output, mantenendo intatto il metodo 'void'. Probabilmente è più desiderabile che il metodo accetti due parametri: InputStream (o Reader) e OutputStream (o Writer o PrintWriter) – Daniel

+0

Hai menzionato i mezzi standard. Significa che ci sono altri modi per testare l'unità? Questo è davvero quello che sto cercando. –

+0

Per testare così com'è, dovresti intercettare i flussi di input e output. Può essere fatto, ma è brutto da morire. – MattPutnam

0

È possibile testare l'uscita con la libreria System Rules.

public class YourTest { 
    @Rule 
    public SystemOutRule log = new SystemOutRule().enableLog(); 
    @Rule 
    public TextFromStandardInputStream systemInMock = emptyStandardInputStream(); 

    @Test 
    public void test() { 
    systemInMock.provideLines("first", "second"); 
    ... //execute your code 
    assertEquals("First!\nSecond!\n", log.getLogWithNormalizedLineSeparator()); 
    } 
} 

Divulgazione completa: sono l'autore di Regole del sistema.