icon | description |
---|---|
flask |
Test your functions! |
CliTester is easy to use, but this page talks about the usage of this library to be able to use it in your console application.
CliTester provides functionality that allows you to define test fixtures that are of the following types:
- Unconditional fixtures: Test fixtures that fall into this category tests against functions that don't return a value (that is, returning
void
). - Conditional fixtures: Test fixtures that fall into this category tests against functions that return a value (that is, returning a value other than
void
).
Fixtures that don't compare the returned value with the expected value and that the function being tested returns void
are unconditional fixtures. This type can be created using the constructor of either a generic version of the FixtureUnconditional
class (i.e. you are required to provide a delegate type that returns void
, such as Action
or Action<string>
) or a non-generic one for dynamic usage.
Unconditional fixtures can be defined like these example declarations:
// Using a generic version
var genericNoArgs = new FixtureUnconditional<Action>(nameof(UnconditionalFunctions.TestWrite), "Tests writing to console", UnconditionalFunctions.TestWrite);
var genericWithArgs = new FixtureUnconditional<Action<string>>(nameof(UnconditionalFunctions.TestWriteArgs), "Tests writing to console with arguments", UnconditionalFunctions.TestWriteArgs, "John");
// Using a non-generic version
var dynamicNoArgs = new FixtureUnconditional(nameof(UnconditionalFunctions.TestWrite), "Tests writing to console", UnconditionalFunctions.TestWrite);
var dynamicWithArgs = new FixtureUnconditional(nameof(UnconditionalFunctions.TestWriteArgs), "Tests writing to console with arguments", UnconditionalFunctions.TestWriteArgs, "John");
Taking into consideration the example target functions that are defined in the UnconditionalFunctions
static class like this:
internal static void TestWrite()
{
Console.WriteLine("Console.WriteLine is called");
Console.WriteLine("Hello world!");
}
internal static void TestWriteArgs(string name)
{
Console.WriteLine("Console.WriteLine is called with arguments");
Console.WriteLine($"Hello, {name}!");
}
In the other hand, fixtures that compare the returned value with the expected value and that the function being tested has a return value are conditional fixtures. This type can be created using the constructor of either a generic version of the FixtureConditional
class (i.e. you are required to provide a delegate type that supports return value, such as Func<int>
or Func<double, double, double>
) or a non-generic one for dynamic usage.
Unconditional fixtures can be defined like these example declarations:
// Using a generic version
var genericNoArgs = new FixtureConditional<Func<int>>(nameof(ConditionalFunctions.TestRead), "Tests reading from console", ConditionalFunctions.TestRead, (int)'A');
var genericWithArgs = new FixtureConditional<Func<double, double, double>>(nameof(ConditionalFunctions.TestReadArgs), "Tests reading from console with arguments", ConditionalFunctions.TestReadArgs, 0d, 4, 2);
// Using a non-generic version
var dynamicNoArgs = new FixtureConditional<Func<int>>(nameof(ConditionalFunctions.TestRead), "Tests reading from console", ConditionalFunctions.TestRead, (int)'A');
var dynamicWithArgs = new FixtureConditional(nameof(ConditionalFunctions.TestReadArgs), "Tests reading from console with arguments", ConditionalFunctions.TestReadArgs, 0d, 4, 2);
Taking into consideration the example target functions that are defined in the ConditionalFunctions
static class like this:
internal static int TestRead()
{
Console.WriteLine("Console.Read is called. Write 'A' in uppercase");
int charNum = Console.Read();
return charNum;
}
internal static double TestReadArgs(double dividend, double divisor) =>
dividend % divisor;
When you need to run the fixtures, you'll need to take these tips into account:
-
Unconditional tests that are defined using the generic version of the
FixtureUnconditional
class can be run using theRunTest<TDelegate>()
function in theFixtureRunner
static class.var fixture = new FixtureUnconditional<Action>(nameof(UnconditionalFunctions.TestWrite), "Tests writing to console", UnconditionalFunctions.TestWrite); bool result = FixtureRunner.RunTest(fixture, out var exc);
-
Unconditional tests that are defined using the non-generic version of the
FixtureUnconditional
class can be run using theRunUnconditionalTest()
function in the fixture runner class.var fixture = new FixtureUnconditional(nameof(UnconditionalFunctions.TestWrite), "Tests writing to console", UnconditionalFunctions.TestWrite); bool result = FixtureRunner.RunUnconditionalTest(fixture, out var exc);
-
Conditional tests that are defined using the generic version of the
FixtureConditional
class can be run using theRunTest<TDelegate, TValue>()
function in theFixtureRunner
static class, but you are required to provide both the delegate type and the value type in theRunTest()
type parameters.var fixture = new FixtureConditional<Func<int>>(nameof(ConditionalFunctions.TestRead), "Tests reading from console", ConditionalFunctions.TestRead, (int)'A'); bool result = FixtureRunner.RunTest<Func<int>, int>(fixture, out var exc);
-
Conditional tests that are defined using the non-generic version of the
FixtureConditional
class can be run using theRunConditionalTest<TValue>()
function in theFixtureRunner
static class, but you are required to provide the value type in theRunConditionalTest()
type parameter.var fixture = new FixtureConditional<Func<int>>(nameof(ConditionalFunctions.TestRead), "Tests reading from console", ConditionalFunctions.TestRead, (int)'A'); bool result = FixtureRunner.RunConditionalTest<int>(fixture, out var exc);
-
Test fixtures can also be run with the
RunGeneralTest()
function if you don't know whether the fixture is unconditional or conditional.var fixture = new FixtureConditional<Func<double, double, double>>(nameof(ConditionalFunctions.TestReadArgs), "Tests reading from console with arguments", ConditionalFunctions.TestReadArgs, 0d, 4, 2); bool result = FixtureRunner.RunGeneralTest(fixture, out var exc);
All the fixture runners return a Boolean value indicating whether the test passed or failed. If the test has passed, then the exception output parameter value is null
. Otherwise, it's populated with exception information that tells you what happened.
To be able to make your console demo application more interactive, you can leverage the use of the fixture selector function that allows the end user to select a test fixture from the full-screen menu. This requires making a new array of type Fixture[]
that stores all the test fixtures that you want. An example of array declaration of all the test fixtures (unconditional or not) is:
Fixture[] fixtures =
[
new FixtureUnconditional<Action>(nameof(UnconditionalFunctions.TestWrite), "Tests writing to console", UnconditionalFunctions.TestWrite),
new FixtureUnconditional<Action<string>>(nameof(UnconditionalFunctions.TestWriteArgs), "Tests writing to console with arguments", UnconditionalFunctions.TestWriteArgs, "John"),
new FixtureConditional<Func<int>>(nameof(ConditionalFunctions.TestRead), "Tests reading from console", ConditionalFunctions.TestRead, (int)'A'),
new FixtureConditional<Func<double, double, double>>(nameof(ConditionalFunctions.TestReadArgs), "Tests reading from console with arguments", ConditionalFunctions.TestReadArgs, 0d, 4, 2),
new FixtureConditional<Func<double, double, double>>(nameof(ConditionalFunctions.TestReadArgs) + "Fail", "Tests reading from console with arguments (failure expected)", ConditionalFunctions.TestReadArgs, 0d, 5, 2),
];
After that, you can use this variable to launch the fixture selector like this:
FixtureSelector.OpenFixtureSelector(fixtures);
If you've defined all the test fixtures correctly, you should now see a menu that looks similar to this:
For each test, there is a status box that indicates whether the test has been run, has succeeded, or has failed.
[ ]
: For tests that are yet to run, this is shown.[*]
: For tests that have succeeded, this is shown.[X]
: For tests that have failed, this is shown.
You can press ENTER to start a test fixture. If the test has succeeded, you'll get a green text saying that the test has passed. If the test has failed, you'll get a red text saying that the test has failed with an error message that may tell you why.
{% hint style="info" %} The fixture selector requires a working terminal which meets Terminaux's requirements. {% endhint %}