Unit Testing System.in for Input Handling in JUnit
Last Updated :
25 Nov, 2024
In Java applications, it’s common to read input from System.in
for interactive console applications. Unit testing such methods can be challenging because they rely on user input. We can achieve this by redirecting System.in to a ByteArrayInputStream
that contains the input we want to simulate.
In this article, we will learn how to perform unit testing of System.in in Java using JUnit.
Maven Dependencies
Include the below JUnit 5 dependencies into the pom.xml file to set up the testing environment.
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
Unit Testing of System.in
The purpose of unit testing is to ensure that individual pieces of code, functions or methods, in isolation are correct. Testing becomes more difficult when a method relies on external input such as the user input through System.in. By default, System.in expects users to provide input through the console, but in automated tests, we want to simulate this input programmatically.
The basic idea is to convert System.in to another input stream, such as ByteArrayInputStream, which allows automatic, repeatable hands-free testing. Basic steps include:
- Redirecting System.in: Use
ByteArrayInputStream
to simulate user input during the test. - Restoring System.in: Ensure that System.in is restored to its original state after the test to avoid side effects on other tests.
- Writing Assertions: Verify the behavior of the code by checking the output or state after processing the input.
Working of System.in Unit Testing
We can replace System.in with any input stream using the System.setIn(InputStream in)
method. For testing purposes, ByteArrayInputStream
can be used to simulate the input. After simulating the input, we can execute the method under test and make assertions to verify that the method behaves as expected.
Example:
Create a Method that Reads from System.in
Let’s create a simple Java class, InputReader
, with a method that reads user input from System.in
and returns it.
public class InputReader {
// This method reads from System.in and returns the input as a String
public String readInput() {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter input: ");
return scanner.nextLine();
}
}
In this class, readInput()
reads a line of input from System.in
and returns it. Normally, this method would wait for user input, but for testing purposes, we will simulate this input.
Simulating System.in
for Testing
To test this method without requiring user interaction, we’ll use ByteArrayInputStream
to simulate System.in
. By setting System.in
to an input stream containing test data, we can automate the input for testing purposes.
Write the JUnit Test Case
Here is a JUnit test for the InputReader
class. We will set System.in
to a ByteArrayInputStream
that contains our simulated user input.
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class InputReaderTest {
private final InputStream originalSystemIn = System.in;
private ByteArrayInputStream testIn;
@BeforeEach
public void setUpInput() {
// This method runs before each test to set up the input
}
@AfterEach
public void restoreSystemIn() {
// Restore System.in after each test
System.setIn(originalSystemIn);
}
@Test
public void testReadInput() {
// Simulate user input "Hello World"
String simulatedInput = "Hello World";
testIn = new ByteArrayInputStream(simulatedInput.getBytes());
System.setIn(testIn);
// Invoke the method to be tested
InputReader inputReader = new InputReader();
String input = inputReader.readInput();
// Assert that the method returns the correct result
assertEquals(simulatedInput, input);
}
}
Project Implementation of System.in Unit Testing With JUnit
Step 1: Create a New Maven Project
Create a new Maven project using IntelliJ IDEA. Choose the following options:
- Name: testing-system-in
- Build system: Maven
Click on the Create button.
Project Structure
After the project creation done, set the folder structure as shown in the below image:
Step 2: Add the JUnit Dependencies to pom.xml
Open the pom.xml
file and add the following JUnit 5 dependencies:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gfg</groupId>
<artifactId>testing-system-in</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- JUnit 5 Dependency -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
</project>
Step 3: Create the UserInput
Class
Create a class named UserInput
to read a number from the user and return its square:
Java
package com.gfg;
import java.util.Scanner;
public class UserInput {
// Method to read a number from the user and return its square
public int readNumberAndSquare() {
Scanner scanner = new Scanner(System.in); // Read from System.in
int number = scanner.nextInt(); // Read an integer from the user
return number * number; // Return the square of the number
}
}
Step 4: Create the Main Class
Create a main class to execute the program:
Java
package com.gfg;
public class Main {
public static void main(String[] args) {
UserInput userInput = new UserInput(); // Create an instance of the class
System.out.println("Please enter a number:"); // Prompt the user for input
int result = userInput.readNumberAndSquare(); // Call the method to get the square of the number
System.out.println("The square of the entered number is: " + result); // Print the result
}
}
Step 5: Create the UserInputTest
Class
To test the UserInput
class, create the following test class:
Java
import com.gfg.UserInput;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class UserInputTest {
@Test
public void testReadNumberAndSquare() {
// Store the original System.in for later restoration
InputStream originalIn = System.in;
try {
// Simulate input for System.in (e.g., user inputs "5")
String input = "5";
ByteArrayInputStream in = new ByteArrayInputStream(input.getBytes());
System.setIn(in); // Redirect System.in to use our simulated input
// Create an instance of the class and call the method
UserInput userInput = new UserInput();
int result = userInput.readNumberAndSquare();
// Assert that the square of 5 is 25
assertEquals(25, result);
} finally {
// Restore the original System.in
System.setIn(originalIn);
}
}
}
Step 6: Run the Application
Once the project is complete, run the Main
class. We will see the below output in the console:
Step 7: Running the Tests
Now, we will run the tests, use the following Maven command in the terminal.
mvn test
Output:
In this article, we demonstrated how to perform unit testing on methods that read from System.in using JUnit.
Conclusion
Simulating System.in in the unit tests is a powerful technique to test the input-dependent methods in the Java. By redirecting the input stream using the ByteArrayInputStream, we can simulate the various user inputs and verify the correctness of the methods. This approach can helps in the automating tests and ensuring the code quality.
Similar Reads
Unit Testing of System.out.println() with JUnit
Unit testing plays a vital role in verifying that individual components of a software application function as intended. One common challenge in unit testing is how to verify the output produced by the System.out.println() method. This method is often used for logging or debugging, but how can you te
3 min read
Inject Parameters into JUnit Jupiter Unit Tests
JUnit 5 (also known as JUnit Jupiter) introduced several new features to enhance the process of writing unit tests. One of the key enhancements is the ability to inject parameters into test methods, simplifying the test setup and making the code more maintainable. Parameterized tests allow the test
8 min read
JUnit Testing For MySQL Project in Java
For testing a software project, automated testing is always good and that will produce error-prone results. In the case of manual testing, there are possibilities of human errors. In this article let us take a sample project and let us see how to write JUnit test cases for it. Example Project Projec
6 min read
How to input text in the text box without calling the sendKeys() using Selenium java?
When automating web applications using Selenium WebDriver, the standard approach to input text into a text box is by using the sendKeys() method. However, there are scenarios where you might want to input text without calling sendKeys(). This can be achieved using JavaScriptExecutor in Selenium. Jav
3 min read
Why is Unit Testing Harder in OOP?
Unit testing is a crucial aspect of software development, serving as the first line of defense against bugs and ensuring the reliability and maintainability of code. Table of Content Steps of Unit TestingChallenges of Unit Testing in OOPStrategies for Overcoming ChallengesExample of unit testingConc
9 min read
Unit Step Signal in Control System
A Control System is a system which manages commands and regulates or directs the behaviour of other devices using control loops. A control system is a device which provides the desired response by controlling the output. A control system can also be defined as a system with a combination of mechanic
9 min read
How to disable an entire unit test in TestNG?
TestNG is an integrated testing framework for Java, which provides several features to support automated testing. As with most test management solutions, a clear need has been seen to be able to comment out selected unit tests so that the code containing them is not removed entirely. In this article
5 min read
JUnit 4 - Conditional Test Execution and Ignoring Strategies
In software testing, there are scenarios where we might to conditionally run or skip the certain tests based on the specific factors, such as operating system, environment variables, or application conditions. JUnit provides various mechanisms to handle these situations. It allows the tests to be ig
9 min read
How to run single test in a TestNG class from IntelliJ IDE?
TestNG is a widely-used testing framework in the Java programming language. Often, when developing or debugging your code, you may need to run a specific test method rather than executing the entire test suite. Fortunately, IntelliJ IDEA makes this task straightforward with its integrated support fo
3 min read
Testing Spring Security Auth with JUnit
Here we are going to learn how to use InMemoryDaoImpl to verify Spring security authentication using a JUnit test case and how to programmatically create a fully complete authentication object and then utilize it in an application. SecurityContextHolder: Spring security is built on the concept of a
4 min read