2017-09-12 6 views
-2

Comment puis-je JUnit tester ma classe de ligne de commande de méthode principale simple qui lit à partir de system.in en utilisant Scanner et imprime à system.out.Comment tester une application de ligne de commande simple en Java en utilisant JUnit

import java.util.Scanner; 

public class SimpleMainCmdApplication { 

    public static void main(String args[]) { 
     Scanner scanner = new Scanner(System.in); 
     System.out.println(scanner.next()); 
    } 
} 

C'est tout à fait un cas d'utilisation spécifique où je fais une structure de données de cours et des algorithmes cours qui demande aux participants de télécharger un fichier * .java avec la principale méthode qui lit à partir System.in (à l'aide du scanner) et renvoie les réponses à System.out. Lorsque vous téléchargez votre code, le site Web crée et exécute l'application, teste et mesure les performances de votre algorithme. Je voulais un moyen de simuler ceci afin que je puisse écrire des tests d'intégration simples en utilisant JUnit dans le cadre d'une approche TDD pour chaque affectation. Il y avait quelques pointeurs utiles sur d'autres threads de débordement de pile qui ont aidé, mais rien qui a rencontré toutes les conditions.

Répondre

0

Pour résoudre ce problème, j'ai créé une méthode privée à partir de laquelle je peux passer les entrées de ligne de commande et le nom de la classe de méthode principale que je veux invoquer avec réflexion. Je peux ensuite appliquer des mactres standard hamcrest à la sortie.

import static org.hamcrest.CoreMatchers.is; 
import static org.junit.Assert.assertThat; 

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.InputStream; 
import java.io.PrintStream; 
import java.lang.reflect.Method; 

import org.junit.Before; 
import org.junit.Test; 

public class MainCmdTest { 

    private ByteArrayOutputStream byteArrayOutputStream; 
    private PrintStream console; 

    @Before 
    public void setup() { 
     byteArrayOutputStream = new ByteArrayOutputStream(); 
     console = System.out; 
    } 

    @Test 
    public void shouldPrintTest() throws Exception { 
     runTest("test", "SimpleMainCmdApplication"); 
     assertThat(byteArrayOutputStream.toString(), is("test\n")); 
    } 

    private void runTest(final String data, final String className) throws Exception { 

     final InputStream input = new ByteArrayInputStream(data.getBytes("UTF-8")); 
     final InputStream old = System.in; 

     try { 
      System.setOut(new PrintStream(byteArrayOutputStream)); 
      System.setIn(input); 

      final Class<?> cls = Class.forName(className); 
      final Method meth = cls.getDeclaredMethod("main", String[].class); 
      final String[] params = new String[]{}; 
      meth.invoke(null, (Object) params); 

     } finally { 
      System.setOut(console); 
      System.setIn(old); 
     } 
    } 
} 

Dans la mise en œuvre effective Je mesure aussi le temps qu'il faut pour exécuter le code et je suis en mesure de fixer des limites de seuil pour effectuer le test.