Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JUnit: How to simulate System.in testing?

I have a Java command-line program. I would like to create JUnit test case to be able to simulate System.in. Because when my program runs it will get into the while loop and waits for input from users. How do I simulate that in JUnit?

Thanks

like image 826
Noppanit Avatar asked Oct 30 '09 03:10

Noppanit


People also ask

Can JUnit be used for system testing?

JUnit can be used as a test runner for any kind of test: e.g. system and integration tests; tests which are interacting with a deployed application.

Can we automate JUnit?

Besides manual testing, JUnit is preferred equally for automation testing. It can also be used along with the Selenium WebDriver to automate tests for web applications. It provides a unique way to write structured, short, and better test cases.

Can you convert JUnit test scripts to testing how?

All you have to do is to put JUnit library on the TestNG classpath, so it can find and use JUnit classes, change your test runner from JUnit to TestNG in Ant and then run TestNG in "mixed" mode. This way you can have all your tests in the same project, even in the same package, and start using TestNG.

How do you run a main method in JUnit?

You can call main method from junit test like this: YourClass. main(new String[] {"arg1", "arg2", "arg3"});


2 Answers

Based on @McDowell's answer and another answer that shows how to test System.out, I would like to share my solution to give an input to a program and test its output.

As a reference, I use JUnit 4.12.

Let's say we have this program that simply replicates input to output:

import java.util.Scanner;  public class SimpleProgram {     public static void main(String[] args) {         Scanner scanner = new Scanner(System.in);         System.out.print(scanner.next());         scanner.close();     } } 

To test it, we can use the following class:

import static org.junit.Assert.*;  import java.io.*;  import org.junit.*;  public class SimpleProgramTest {     private final InputStream systemIn = System.in;     private final PrintStream systemOut = System.out;      private ByteArrayInputStream testIn;     private ByteArrayOutputStream testOut;      @Before     public void setUpOutput() {         testOut = new ByteArrayOutputStream();         System.setOut(new PrintStream(testOut));     }      private void provideInput(String data) {         testIn = new ByteArrayInputStream(data.getBytes());         System.setIn(testIn);     }      private String getOutput() {         return testOut.toString();     }      @After     public void restoreSystemInputOutput() {         System.setIn(systemIn);         System.setOut(systemOut);     }      @Test     public void testCase1() {         final String testString = "Hello!";         provideInput(testString);          SimpleProgram.main(new String[0]);          assertEquals(testString, getOutput());     } } 

I won't explain much, because I believe the code is readable and I cited my sources.

When JUnit runs testCase1(), it is going to call the helper methods in the order they appear:

  1. setUpOutput(), because of the @Before annotation
  2. provideInput(String data), called from testCase1()
  3. getOutput(), called from testCase1()
  4. restoreSystemInputOutput(), because of the @After annotation

I didn't test System.err because I didn't need it, but it should be easy to implement, similar to testing System.out.

like image 35
Antônio Medeiros Avatar answered Oct 02 '22 15:10

Antônio Medeiros


It is technically possible to switch System.in, but in general, it would be more robust not to call it directly in your code, but add a layer of indirection so the input source is controlled from one point in your application. Exactly how you do that is an implementation detail - the suggestions of dependency injection are fine, but you don't necessarily need to introduce 3rd party frameworks; you could pass round an I/O context from the calling code, for example.

How to switch System.in:

String data = "Hello, World!\r\n"; InputStream stdin = System.in; try {   System.setIn(new ByteArrayInputStream(data.getBytes()));   Scanner scanner = new Scanner(System.in);   System.out.println(scanner.nextLine()); } finally {   System.setIn(stdin); } 
like image 99
McDowell Avatar answered Oct 02 '22 17:10

McDowell