Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add testing documentation #1631

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
5 changes: 3 additions & 2 deletions docs/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ await Bootstrapper.Factory
{
"../../src/Spectre.Console/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
"../../src/Spectre.Console.Cli/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
"../../src/Spectre.Console.ImageSharp/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
"../../src/Spectre.Console.Json/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs"
"../../src/Spectre.Console.Testing/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
"../../src/Extensions/Spectre.Console.ImageSharp/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
"../../src/Extensions/Spectre.Console.Json/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs"
})
.AddSetting(Constants.ExampleSourceFiles, new List<string>
{
Expand Down
6 changes: 2 additions & 4 deletions docs/input/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,8 @@ on the main thread.
### Unit Testing Best Practices

For testing of console output, Spectre.Console has [`IAnsiConsole`](xref:T:Spectre.Console.IAnsiConsole) that can be
injected into your application.
The [Spectre.Console.Test](https://www.nuget.org/packages/Spectre.Console.Testing/) contains a set of utilities for
capturing the output for verification, either manually or via a tool such
as [Verify](https://github.com/VerifyTests/Verify).
injected into your application. The [Spectre.Console.Test](https://www.nuget.org/packages/Spectre.Console.Testing/)
NuGet package contains utilities for capturing the console output for verification. See the [Unit Testing](cli/unit-testing) page for further guidance.

### Analyzer for Best Practices

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ New features have been added, such as the ability to show separators between tab
## Rendering

* Add .NET 8 support by [@patriksvensson](https://github.com/patriksvensson) in [#1367](https://github.com/spectreconsole/spectre.console/pull/1367)
* Fixed render issue where writeline inside status caused corrupt output #415 #694 by [@fredrikbentzen](https://github.com/fredrikbentzen) in [#1132]([#1132](https://github.com/spectreconsole/spectre.console/pull/1132))
* Relax the SDK requirements by rolling forward to the latest feature by [@0xced](https://github.com/0xced) in [#1237]([#1237](https://github.com/spectreconsole/spectre.console/pull/1237))
* Add fix to avoid exception on rows with no children by [@jeppevammenkristensen](https://github.com/jeppevammenkristensen) in [#1241]([#1241](https://github.com/spectreconsole/spectre.console/pull/1241))
* Fixed render issue where writeline inside status caused corrupt output #415 #694 by [@fredrikbentzen](https://github.com/fredrikbentzen) in [#1132](https://github.com/spectreconsole/spectre.console/pull/1132)
* Relax the SDK requirements by rolling forward to the latest feature by [@0xced](https://github.com/0xced) in [#1237](https://github.com/spectreconsole/spectre.console/pull/1237)
* Add fix to avoid exception on rows with no children by [@jeppevammenkristensen](https://github.com/jeppevammenkristensen) in [#1241](https://github.com/spectreconsole/spectre.console/pull/1241)
* Set `end_of_line` to `LF` instead of `CRLF` by [@0xced](https://github.com/0xced) in [#1256](https://github.com/spectreconsole/spectre.console/pull/1256)
* Fix `Rule` widget docs by [@tomaszprasolek](https://github.com/tomaszprasolek) in [#1257](https://github.com/spectreconsole/spectre.console/pull/1257)
* Added the missing columns-cast by [@nils](https://github.com/nils)-a in [#1294](https://github.com/spectreconsole/spectre.console/pull/1294)
Expand All @@ -46,7 +46,7 @@ New features have been added, such as the ability to show separators between tab

## CLI
* Add async command unit tests by [@FrankRay78](https://github.com/FrankRay78) in [#1228](https://github.com/spectreconsole/spectre.console/pull/1228)
* Add support for async delegate by [@icalvo](https://github.com/icalvo) in [#1215]([#1215](https://github.com/spectreconsole/spectre.console/pull/1215))
* Add support for async delegate by [@icalvo](https://github.com/icalvo) in [#1215](https://github.com/spectreconsole/spectre.console/pull/1215)
* Remove unnecessary `[NotNull]` attributes by [@0xced](https://github.com/0xced) in [#1255](https://github.com/spectreconsole/spectre.console/pull/1255)
* Allow custom help providers by [@FrankRay78](https://github.com/FrankRay78) in [#1259](https://github.com/spectreconsole/spectre.console/pull/1259)
* Specified details for settings for the argument vector by [@nils](https://github.com/nils)-a in [#1301](https://github.com/spectreconsole/spectre.console/pull/1301)
Expand Down
115 changes: 115 additions & 0 deletions docs/input/cli/unit-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
Title: Unit Testing
Order: 14
Description: Instructions for unit testing a Spectre.Console application.
Reference:
- T:Spectre.Console.Testing.CommandAppTester
- T:Spectre.Console.Testing.TestConsole
- T:Spectre.Console.Testing.TestConsoleInput
---

`Spectre.Console` has a separate project that contains test harnesses for unit testing your own console applications.

The fastest way of getting started is to install the `Spectre.Console.Testing` NuGet package.

```text
> dotnet add package Spectre.Console.Testing
```

`Spectre.Console.Testing` is also the namespace containing the test classes.

## Testing a CommandApp

The `CommandAppTester` is a test implementation of `CommandApp` that's configured in a similar manner but designed for unit testing.

The following example validates the exit code and terminal output of a `Spectre.Console` command:

```csharp
/// <summary>
/// A Spectre.Console Command
/// </summary>
public class HelloWorldCommand : Command
{
private readonly IAnsiConsole _console;

public HelloWorldCommand(IAnsiConsole console)
{
// nb. AnsiConsole should not be called directly by the command
// since this doesn't play well with testing. Instead,
// the command should inject a IAnsiConsole and use that.

_console = console;
}

public override int Execute(CommandContext context)
{
_console.WriteLine("Hello world.");
return 0;
}
}

[TestMethod]
public void Should_Output_Hello_World()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<HelloWorldCommand>();

// When
var result = app.Run();

// Then
Assert.AreEqual(result.ExitCode, 0);
Assert.AreEqual(result.Output, "Hello world.");
}
```

## Testing console behaviour

`TestConsole` and `TestConsoleInput` are testable implementations of `IAnsiConsole` and `IAnsiConsoleInput`, allowing you fine-grain control over testing console output and interactivity.

The following example renders some widgets before then validating the console output:

```csharp
[TestMethod]
public void Should_Render_Panel()
{
// Given
var console = new TestConsole();

// When
console.Write(new Panel(new Text("Hello World")));

// Then
Assert.AreEqual(console.Output, """"
┌─────────────┐
│ Hello World │
└─────────────┘

"""");
}
```

While `Assert` is fine for validating simple output, more complex output may benefit from a tool like [Verify](https://github.com/VerifyTests/Verify).

The following example prompts the user for input before then validating the expected choice was made:

```csharp
[TestMethod]
public void Should_Select_Orange()
{
// Given
var console = new TestConsole();
console.Input.PushTextWithEnter("Orange");

// When
console.Prompt(
new TextPrompt<string>("Favorite fruit?")
.AddChoice("Banana")
.AddChoice("Orange"));

// Then
Assert.AreEqual(console.Output, "Favorite fruit? [Banana/Orange]: Orange\n");
}
```

`CommandAppTester` uses `TestConsole` internally, which in turn uses `TestConsoleInput`, offering a fully testable harness for `Spectre.Console` widgets, prompts and commands.
14 changes: 9 additions & 5 deletions docs/input/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,27 @@ Order: 0
Spectre.Console is a `.NET` library that makes it easier
to create beautiful console applications.

## Spectre.Console.AnsiConsole Features
## Spectre.Console.AnsiConsole

* Easily output text with different colors and even styles such as bold, italic and blinking with a Rich inspired [markup language](markup).
* Supports `3`/`4`/`8`/`24`-bit colors in the terminal with auto-detection of the current terminal's capabilities.
* Render complex [widgets](widgets) such as [tables](widgets/table), [trees](widgets/tree), and even [ASCII images](widgets/canvas-image).
* Display progress for long running tasks with live displays of [progress](live/progress) and [status](live/status) controls.
* Prompt user input with strongly typed [text input](prompts/text) or via [single-item select](prompts/selection) and [multiple item select](prompts/multiselection) controls.
* Format .NET [exceptions](exceptions) with custom color coded themes and styles.
* Written with unit testing in mind.

Spectre.Console.AnsiConsole has been heavily inspired
by the excellent [Rich](https://github.com/willmcgugan/rich) library
for Python written by Will McGugan.
Spectre.Console.AnsiConsole has been heavily inspired by the excellent [Rich](https://github.com/willmcgugan/rich) library for Python written by Will McGugan.

## Spectre.Console.Cli

* Create strongly typed settings and commands for parsing `args[]` to create complex command line applications like `git`, `gh`, or `dotnet`

## Spectre.Console.Testing

* Spectre.Console has been developed with unit testing in mind. The Spectre.Console library itself is covered by an extensive test suite, project maintainers require test coverage for all new commits, and the same extension points and test harnesses used internally for testing are available to you.

* The [Unit Testing](cli/unit-testing) page provides instructions for testing a Spectre.Console application.

## Examples

![Sample of Spectre.Console output](./assets/images/example.png)
Expand All @@ -36,3 +39,4 @@ for Python written by Will McGugan.
Sorry, your browser doesn't support embedded videos.
</video>

The Spectre.Console [examples repository](https://github.com/spectreconsole/examples) contains many other examples.
3 changes: 1 addition & 2 deletions docs/src/Pipelines/CodePipeline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ public Api()
new ConcatDocuments(nameof(Code)),
new CacheDocuments(
new AnalyzeCSharp()
.WhereNamespaces(ns => ns.StartsWith("Spectre.Console") && !ns.Contains("Analyzer") &&
!ns.Contains("Testing") && !ns.Contains("Examples"))
.WhereNamespaces(ns => ns.StartsWith("Spectre.Console") && !ns.Contains("Analyzer") && !ns.Contains("Examples"))
.WherePublic(true)
.WithCssClasses("code", "cs")
.WithDestinationPrefix("api")
Expand Down