Using the nanoFramework.TestPlatform
The core component to prepare your test is nanoFramework.TestPlatform
.
The attributes
The classes and tests methods are recognized using attributes. You'll find the following ones:
[TestClass]
: this attribute is used on a class, without this attribute on the calls, the class won't be considered as a a valid Unit Test and the test methods inside will be ignored. You can have as many classes as you want with this attribute. Each class can then contain as many tests methods, setup and cleanup as you want.[TestMethod]
: this attribute is used on any method where you'll have tests running inside. You can have as many methods with this attribute as you want.[Setup]
: this attribute is used on any method. This test will be called first. While you technically have as many of those functions per class, it is recommended to only use 1 per class. Typical usage is to setup hardware you'll need to have running for all the tests methods.[Cleanup]
: this attribute is used on any method. This test will be called last, after the all the tests methods. While you technically have as many of those functions per class, it is recommended to only use 1 per class.
Attributes usage
Here is a typical example of how you can use the attributes:
namespace nanoFramework.TestFramework.Test
{
[TestClass]
public class TestOfTest
{
[TestMethod]
public void TestRaisesException()
{
Debug.WriteLine("Test will raise exception");
Assert.Throws(typeof(Exception), ThrowMe);
}
private void ThrowMe()
{
throw new Exception("Test failed and it's a shame");
}
[Setup]
public void RunSetup()
{
Debug.WriteLine("Setup");
}
[TestMethod]
public void TestStringComparison()
{
Debug.WriteLine("Test string, Contains, EndsWith, StartWith");
// Arrange
string tocontains = "this text contains and end with contains";
string startcontains = "contains start this text";
string contains = "contains";
string doesnotcontains = "this is totally something else";
string empty = string.Empty;
string stringnull = null;
// Assert
Assert.Contains(contains, tocontains);
Assert.DoesNotContains(contains, doesnotcontains, "Your own error message");
Assert.DoesNotContains(contains, empty);
Assert.DoesNotContains(contains, stringnull);
Assert.StartsWith(contains, startcontains);
Assert.EndsWith(contains, tocontains);
}
[TestMethod]
public void MethodWillSkippIfFloatingPointSupportNotOK()
{
var sysInfoFloat = SystemInfo.FloatingPointSupport;
if ((sysInfoFloat != FloatingPoint.DoublePrecisionHardware) && (sysInfoFloat != FloatingPoint.DoublePrecisionSoftware))
{
Assert.SkipTest("Double floating point not supported, skipping the Assert.Double test");
}
double on42 = 42.1;
double maxDouble = double.MaxValue;
Assert.Equal(42.1, on42);
Assert.Equal(double.MaxValue, maxDouble);
}
public void Nothing()
{
Debug.WriteLine("Nothing and should not be called");
}
[Cleanup]
public void Cleanup()
{
Debug.WriteLine("Cleanup");
}
}
}
As you can see in this example, you just use the attributes to decorate the class and the functions.
Functions should be void
type and take no argument at all.
The test pass if there is no exception happening in the function. If any exception happens in the function, it is considered as failed.
Function visibility
All functions with attributes for testing must be public void
, if you set them as private or internal, they won't be discovered.
Asserting in the test functions
As for most of the famous .NET Unit Test platform, the concept of Assert
is present as well in .NET nanoFramework. You can see in the previous example some of those Assert
functions. They take one or two arguments and are straight forward to use.
If there is an issue in those Assert function, an exception is raised.
Note that all the Assert
functions can pass a custom message. For example: Assert.Equal(42, 43, "My custom message saying that 42 is not equal to 43");
Assert.Throws
This checks if a specific function will throw an exception. Usage:
Assert.Throws(typeof(ExceptionTypeToCatch), AFunctionToCall);
Where:
ExceptionTypeToCatch
has to be a type of Exception. Typical example is to check if the function you're trying to call rases aArgumentException
for example.AFunctionToCall
is anAction
, so a function you can call to check if an exception is raised.
See the pattern in the previous example.
Assert.True and Assert.False
Simply check if something is True or False
bool boola = true;
Assert.True(boola);
Assert.Equal and Asset.NotEqual
Assert.Equal
is collection of functions that takes all the native Value Types as well as Array and check if the elements in the array are equals (if value) or same object (for non value types).
Assert.Equal(elementa, elementb);
Same behavior for Assert.NotEqual
but checking that the 2 elements are not equal.
Assert.NotEqual(elementa, elementb);
Assert.Null and Assert.NotNull
Those functions check that an element is null or not null.
object objnull = null;
object objnotnull = new object();
Assert.Null(objnull);
Assert.NotNull(objnotnull);
Assert.IsType and Assert.IsNotType
Those functions allows to check that an element is a specific type or not a specific type.
Type typea = typeof(int);
Type typeb = typeof(int);
Type typec = typeof(long);
Assert.IsType(typea, typeb);
Assert.IsNotType(typea, typec);
Assert.Empty and Assert.NotEmpty
Assert.Same and Assert.NotSame
Functions to check that objects are the same or different.
object obja = new object();
object objb = new object();
Assert.NotSame(obja, objb);
objb = obja;
Assert.Same(obja, objb);
Assert for String checking
A set of functions to help checking strings is available. They allow most of the common scenarios, checking that a string contains specific elements, start with, end with as well as not containing some elements.
// Arrange
string tocontains = "this text contains and end with contains";
string startcontains = "contains start this text";
string contains = "contains";
string doesnotcontains = "this is totally something else";
string empty = string.Empty;
string stringnull = null;
// Assert
Assert.Contains(contains, tocontains);
Assert.DoesNotContains(contains, doesnotcontains);
Assert.DoesNotContains(contains, empty);
Assert.DoesNotContains(contains, stringnull);
Assert.StartsWith(contains, startcontains);
Assert.EndsWith(contains, tocontains);
Outputting messages from the tests
It's possible to output messages from the Unit Tests using OutputHelper.Write
and OutputHelper.WriteLine
. These work exactly as Debug.Write
and Debug.WriteLine
so simple or formatted output is available.
OutputHelper.WriteLine("This is a message from Unit Test XYZ!");
OutputHelper.WriteLine($"This is another message from Unit Test XYZ, showing that {someVariable.Length} can be output too.");
Skipping a test
You can skip a test by using Assert.SkipTest
. You can place an explanation like this:
Assert.SkipTest("Double floating point not supported, skipping the Assert.Double test");
Important: if you skip the Setup
test, all the class TestMethod
will be skipped as well. This is a convenient way to skip some specific hardware tests if the current hardware does not support them for example. This will allow to build different classes for different hardware for example and having only the right tests being executed.