To test CLI applications, use CommandAppTester from Spectre.Console.Cli.Testing. It runs commands in-memory and captures exit codes and output for assertions.
Make Commands Testable
Inject IAnsiConsole instead of using the static AnsiConsole directly. This allows tests to capture output:
public class GreetCommand : Command<GreetCommand.Settings>
{
private readonly IAnsiConsole _console;
public class Settings : CommandSettings
{
[CommandArgument(0, "<name>")]
[Description("Name to greet")]
public string Name { get; init; } = string.Empty;
[CommandOption("-c|--count")]
[Description("Number of times to greet")]
[DefaultValue(1)]
public int Count { get; init; } = 1;
}
public GreetCommand(IAnsiConsole console)
{
_console = console;
}
protected override int Execute(CommandContext context, Settings settings, CancellationToken cancellation)
{
for (var i = 0; i < settings.Count; i++)
{
_console.MarkupLine($"Hello, [green]{settings.Name}[/]!");
}
return 0;
}
}
Test with CommandAppTester
Install the testing package:
dotnet add package Spectre.Console.Cli.Testing
Configure the tester like a regular CommandApp, then call Run with arguments. The result provides ExitCode, Output, and Settings for assertions:
[Fact]
public void Greet_WithName_ReturnsZeroAndOutputsGreeting()
{
// Arrange
var app = new CommandAppTester();
app.SetDefaultCommand<GreetCommand>();
// Act
var result = app.Run("World");
// Assert
Assert.Equal(0, result.ExitCode);
Assert.Contains("Hello", result.Output);
Assert.Contains("World", result.Output);
}
You can also verify that command-line arguments were parsed correctly:
[Fact]
public void Greet_WithCount_ParsesSettingsCorrectly()
{
// Arrange
var app = new CommandAppTester();
app.SetDefaultCommand<GreetCommand>();
// Act
var result = app.Run("Alice", "--count", "3");
// Assert
Assert.Equal(0, result.ExitCode);
// Verify settings were parsed correctly
var settings = result.Settings as GreetCommand.Settings;
Assert.NotNull(settings);
Assert.Equal("Alice", settings!.Name);
Assert.Equal(3, settings.Count);
}
Test Interactive Prompts
For commands with prompts, use TestConsole to queue input before running:
[Fact]
public void Interactive_WithQueuedInput_ProcessesCorrectly()
{
// Arrange - queue up user input before running
var console = new TestConsole();
console.Profile.Capabilities.Interactive = true;
console.Input.PushTextWithEnter("yes");
var app = new CommandAppTester(console: console);
app.SetDefaultCommand<ConfirmCommand>();
// Act
var result = app.Run();
// Assert
Assert.Equal(0, result.ExitCode);
Assert.Contains("Confirmed", result.Output);
}
Use PushKey for arrow keys and enter, PushTextWithEnter for text input.
See Also
- Dependency Injection in CLI Apps - Inject IAnsiConsole via DI
- Handling Errors and Exit Codes - Test error scenarios