A toolkit for improving self documentation, readability, and debugging of tests.
PHX.Test assists in setting up a BDD given/when/then structure for readability and test self-documentation, and it logs each provided value, input, output, condition, action, and assertion in human readable text to assist in debugging what is occurring in a test and what is going wrong.
This test class using Phx.Test:
[TestFixture]
[FixtureLifeCycle(LifeCycle.InstancePerTestCase)]
[Parallelizable(ParallelScope.All)]
public class AccumulatorTests : LoggingTestClass {
[Test]
public void APositiveValueCanBeAdded() {
var accumulator = Given("An accumulator instance", () => new Accumulator());
var valueToAdd = Given("A positive number", () => 10);
When("The value is added to the accumulator", () => accumulator.Add(valueToAdd));
Then("The accumulator has the expected total",
10,
(expected) => {
Verify.That(accumulator.Total.IsEqualTo(expected));
});
}
[Test]
public void ANegativeValueCannotBeAdded() {
var accumulator = Given("An accumulator instance", () => new Accumulator());
var valueToAdd = Given("A negative number", () => -10);
var action = DeferredWhen("The value is added to the accumulator",
() => accumulator.Add(valueToAdd));
Then("The expected exception is thrown",
typeof(InvalidOperationException),
(expectedExceptionType) => { Verify.That(action.DoesThrow(expectedExceptionType)); });
}
}
Will generate the following output:
----------------------------------------
## Phx.Test.Example.AccumulatorTests.APositiveValueCanBeAdded
**Given:**
* An accumulator instance : `Phx.Test.Example.Accumulator` -> **PASSED**
* A positive number : `10` -> **PASSED**
**When:**
* The value is added to the accumulator -> **PASSED**
**Then:**
* The accumulator has the expected total (`10`) -> **PASSED**
> TestResult: **PASSED**
----------------------------------------
## Phx.Test.Example.AccumulatorTests.ANegativeValueCannotBeAdded
**Given:**
* An accumulator instance : `Phx.Test.Example.Accumulator` -> **PASSED**
* A negative number : `-10` -> **PASSED**
**When:**
* The value is added to the accumulator -> **DEFERRED**
**Then:**
* A deferred action is executed: `The value is added to the accumulator` -> **PASSED**
* The expected exception is thrown (`System.InvalidOperationException`) -> **PASSED**
> TestResult: **PASSED**
PHX.Test can be installed as a Nuget package using the .NET CLI.
dotnet add package Phx.Test
PHX.Test is built on top of NUnit, and the only thing that is necessary to get
started is to write a test class that extends Phx.Test.LoggingTestClass
.
[TestFixture]
public class AccumulatorTests : LoggingTestClass {
// ...
}
The class will have access to the Given
, When
, DeferredWhen
, Then
, and
Log
methods used to log test values and actions.
Following conventions of BDD:
Given
should be used to log test preconditions and input values, and will return the value for use in later test steps.When
should be used to log the action under test and returns the result of the action for validation.DeferredWhen
should be used when execution of the action under test must be delayed to validate it correctly. This is typically used in conjunction with a Then step to verify an exception was or was not thrown. If a deferred action is not executed by the time the test completes, the test will fail.Then
should be used to validate the results of the action. An expected value can be passed in to be logged.Log
can also be used to log any test messages that you want to appear inline in the test logs.Pending
is used to indicate that a test's implementation is pending completion. By default, pending tests will cause a failure. Setting thePHX_TEST_FAIL_ON_PENDING
env var tofalse
or overriding the test class'sFailOnPending
property to returnfalse
will cause the test to complete successfully and ignore the pending scenario.
PHX.Test also provides utilities to make writing and debugging tests easier.
TestDisposable
is an IDisposable
that allows you to manually initialize it
in a desired disposed state, and to check the current disposed state.
var disposable = new TestDisposable(false);
Verify.That(disposable.IsDisposed.IsFalse());
disposable.Dispose();
Verify.That(disposable.IsDisposed.IsTrue());
This can be useful when testing types that contain or manipulate IDisposable
instances.
TestException
is a simple exception type that can be thrown from mocked or
test code and is easily distinguishable from any exception that may be thrown
from production code.
var action = () => {
PerformAction(() => { throw new TestException("This is a test."); }
}
// We know `TestException` was thrown by our test code and not something else
// inside of the `PerformAction` method.
Verify.That(action.DoesThrow<TestException>());
Verify
is a PHX.Validation
validator that will throw a VerificationFailedException
when the validation
fails.
Test validator extension methods are also provided to help verify that an
exception was thrown by an Action
.
Verify.That(action.DoesThrow<TestException>());
Licensed under the Apache License, Version 2.0.
See http://www.apache.org/licenses/LICENSE-2.0 for full license information.