How to Mock System.in and System.out for Java Unit Tests

This guide shows how to replace System.in and System.out with in‑memory streams during unit testing, provides reusable helper classes for setting and restoring these streams, and includes a complete example demonstrating input simulation and output capture in Java.

FunTester
FunTester
FunTester
How to Mock System.in and System.out for Java Unit Tests

Mocking System.in and System.out in Java Unit Tests

When a unit test depends on user input via Scanner scanner = new Scanner(System.in), you can replace System.in and System.out with in‑memory streams to simulate input and capture output without manual interaction.

public MockInOut(String input) {
    orig = System.out;
    irig = System.in;

    os = new ByteArrayOutputStream();
    try {
        System.setOut(new PrintStream(os, false, charset.name()));
    } catch (UnsupportedEncodingException ex) {
        throw new RuntimeException(ex);
    }

    is = new ByteArrayInputStream(input.getBytes());
    System.setIn(is);
}

The constructor saves the original System.out and System.in, redirects System.out to a ByteArrayOutputStream, and feeds the supplied input string to a ByteArrayInputStream. After this setup, calls such as scanner.nextLine() read the prepared input instantly, and any calls to System.out.println write to the buffer instead of the console.

public void close() {
    os = null;
    is = null;
    System.setOut(orig);
    System.setIn(irig);
}

Calling close() restores the original streams, allowing the test environment to return to its normal state.

import java.io.*;
import java.util.*;

class HelloWorld {
    public static void main(String[] args) throws IOException {
        PrintStream orig = System.out;
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        System.setOut(new PrintStream(os, false, "UTF-8"));
        // No console output here
        for (int i = 0; i < 2; i++) {
            System.out.println("FunTester" + i);
        }
        System.setOut(orig);
        // Print the captured output
        output("Collected output: " + os.toString("UTF-8"));

        InputStream is = System.in;
        System.setIn(new ByteArrayInputStream("FunTester
FunTester
".getBytes()));
        Scanner scanner = new Scanner(System.in);
        // Output all captured input lines
        output(scanner.nextLine());
        output(scanner.nextLine());
        try {
            // This will throw because there is no more input
            System.out.println(scanner.nextLine());
        } catch (NoSuchElementException e) {
            e.printStackTrace();
        }

        System.setIn(is);
        scanner = new Scanner(System.in);
        // This will wait for user input
        System.out.println("Input: " + scanner.nextLine());
    }
}

This simple approach demonstrates how injecting and swapping streams can isolate I/O dependencies in unit tests, allowing you to focus on the logic under test. More sophisticated mocking frameworks exist, but the presented technique is lightweight and easy to integrate.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaunit testingmockingIO StreamsSystem.inSystem.outtesting-utilities
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.