Test-Driven Test Development
Writing a Red Test
Integration Tests
Back in the root of our project folder, let’s create a project using an existing .NET testing framework.
At the time of writing, there are a many choices to choose from: xUnit, NUnit, MSTest, and more.
To make this tutorial easier for most developers out there, let’s use the most popular one: xUnit
Let’s make a new xUnit test project now by running this command from the root project folder:
dotnet new xunit -n MiniSpec.Specs
This will create a new project folder MiniSpec.Specs/. Let’s go there and write an integration test!
We’ll create a test which:
- Runs
minispec.exewith theMyTests.dllDLL assembly provided as an argument - Asserts that the output contains text which indicates that
TestShouldPass()passed - Asserts that the output contains text which indicates that
TestShouldFail()failed
What is
minispec.exe? It doesn’t exist yet, but that’s the program we’ll make to run tests!
Rename UnitTest1.cs to IntegrationTest.cs and replace its content with the following:
IntegrationTest.cs
using Xunit;
public class IntegrationTest {
[Fact]
public void ExpectedSpecsPassAndFail() {
// Arrange
var minispecExe = System.IO.File.Exists("minispec.exe") ?
"minispec.exe" : "minispec"; // No .exe extension on Linux
using var minispec = new System.Diagnostics.Process {
StartInfo = {
RedirectStandardOutput = true, // Get the StandardOutput
RedirectStandardError = true, // Get the StandardError
FileName = minispecExe,
Arguments = "MyTests.dll"
}
};
// Act
minispec.Start();
minispec.WaitForExit();
var StandardOutput = minispec.StandardOutput.ReadToEnd();
var StandardError = minispec.StandardError.ReadToEnd();
var output = $"{StandardOutput}{StandardError}";
minispec.Kill();
// Assert
Assert.Contains("PASS TestShouldPass", output);
Assert.Contains("FAIL TestShouldFail", output);
Assert.Contains("Kaboom!", output);
}
}
Review
So, what’s happening here?
- We assume that there will be a
minispec.exeexecutable (or simplyminispecon Linux). - We invoke the
minispec.exeprocess passing the DLL with our defined tests as an argument. - We read StandardOutput and StandardError from the process result, i.e. all of the program’s console output.
- StandardOutput and StandardError are combined because we don’t currently care which the results output to.
- We look for expected messages in the output, e.g.
PASS [testname]orFAIL [testname]
We’re totally making up some of these things as we go along, e.g. the
PASS/FAILmessages.
This is how TDD works. We just need to make it fail, then pass, then we can change it later!