Skip to content

Output tests and program input ​

Most challenges test a function: the test imports it, calls it and checks the result. Beginners who have not met functions yet need something simpler. Output tests run the learner's whole program, give it some text on standard input and compare what it printed — the way a terminal would.

When to use them

"Print Hello World", "Read a name and greet it", "Print the numbers from 1 to 10": any task where the program is the solution. Once the learner knows functions, prefer regular tests.

How an output test works ​

The test file calls a small helper that DojoCode drops next to the sources while the tests run. The helper starts the main file, writes the given text to its standard input, waits for it to finish and returns what it printed, with trailing spaces and newlines trimmed. The helper exists only during a test run — never create it yourself.

A challenge switches to output tests as soon as a test file references the helper. Nothing changes for challenges that do not.

TemplateImportCall
Pythonfrom challenge.dojo_io import runrun("Ana\n")
Node.js / Node TSimport { run } from 'dojo-io'run('Ana\n')
PHP— (DojoIO is global)DojoIO::run("Ana\n")
Ruby— (DojoIO is global)DojoIO.run("Ana\n")
Java— (DojoIO is in the challenge package)DojoIO.run("Ana\n")
C#— (DojoIO is in the Challenge namespace)DojoIO.Run("Ana\n")
Go— (DojoRun is in package main)DojoRun(t, "Ana\n")
Rustuse crate::dojo_io::run;run("Ana\n")
C#include "dojo_io.h"dojo_run("Ana\n")
C++#include "dojo_io.hpp"dojo_run("Ana\n")

The argument is the text the program reads from standard input, one line per value ("3\n4\n" for two numbers). For programs that read nothing, pass an empty string; most helpers also let you leave the argument out, but Go, Rust and C require it.

Example: Greet by name ​

The learner reads a name and prints Hello, <name>!. The preloaded main file is a stub with the task in a comment, and the main file is the solution: there is no separate solution file to import.

py
name = input()
print(f"Hello, {name}!")
py
from pytest import mark as m
from challenge.dojo_io import run


@m.describe("Greet by name")
class TestGreetByName:
    @m.it("greets Ana")
    def test_greets_ana(self):
        assert run("Ana\n") == "Hello, Ana!"

    @m.it("greets Mihai Popescu")
    def test_greets_mihai_popescu(self):
        assert run("Mihai Popescu\n") == "Hello, Mihai Popescu!"
java
package challenge;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class GreetByNameTest {
    @Test
    @DisplayName("greets Ana")
    void greetsAna() {
        assertEquals("Hello, Ana!", DojoIO.run("Ana\n"));
    }
}
c
#include <criterion/criterion.h>
#include "dojo_io.h"

Test(greet_by_name, greets_ana, .description = "greets Ana") {
    cr_assert_str_eq(dojo_run("Ana\n"), "Hello, Ana!");
}

Use several inputs per behavior, and keep some only in the full test suite, so a hard-coded print("Hello, Ana!") cannot pass.

Rules for programs that read input ​

  • Do not print a prompt. Everything the program writes to standard output is part of the comparison, so Console.Write("Name: ") before ReadLine() makes the test expect Name: Hello, Ana!. The one exception is Python: the helper hides the text passed to input("Name: "), so Python programs may prompt.
  • Read whole lines and trim them: input(), gets.chomp, scanner.nextLine(), fgets + strcspn, std::getline, read_line + trim. The template pages show the idiom for each language.
  • Every value on its own line. Tell the learner the exact format in the description ("the first line holds the name") and feed the tests the same way.
  • With no input, the program gets end-of-file, not a hang: input() raises EOFError, gets returns nil, ReadLine() returns null. A program that reads nothing is unaffected.

Run versus Test ​

Test feeds the program whatever the test passes to the helper. Run executes the main file alone, in an interactive terminal: the learner sees the prompt and types the answer, like in a real terminal, and the program may run for up to 5 minutes in total, but it is stopped after 2 minutes in which nothing happens (no output and no input). Nothing to configure — every terminal template runs this way.

In the editor, the AI assistant's run_code tool cannot type into a terminal; it passes the input as its stdin argument (one line per value) instead, so it can still try an input-reading program for you.

For Python challenges with the browser preview on, input() in the preview opens the browser's own dialog instead; see the Python template.

Structure checks ​

Output tests can also check how the program is written when the task prescribes a construct ("use a for loop", "do not use while"). The same helper exposes uses("for"), count("if"), defines("average") (a function), declares("total") (a variable) and friends. They say that a construct exists, not that it does the right thing, so always pair them with output tests.