C# NUnit cheatsheet with code examples.
using System;
using System.Reflection;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
namespace NUnitCheatSheet
{
/// <summary>
/// TestFixtureSetUp: Provides a config class for setting up and tearing down the test fixture.
/// Provides the config for all TestFixture classes witin the same namespace.
/// </summary>
[SetUpFixture]
public class TestFixtureSetUp
{
/// <summary>
/// SetUp; run once before all tests in a test fixture.
/// Run once for each TestFixture in the same namespace.
/// </summary>
[SetUp]
public void RunBeforeAnyTests()
{
// Set up code here.
}
/// <summary>
/// TearDown; run once after all tests in a test fixture.
/// Run once for each TestFixture in the same namespace.
/// </summary>
[TearDown]
public void RunAfterAnyTests()
{
// Clear up code here.
}
}
/// <summary>
/// Factory class for providing test data for tests with the TestCaseSource attribue.
/// </summary>
public class TestCaseDataFactory
{
/// <summary>
/// TestCaseSource tests can consume IEnumerable properties which return TestCaseData
/// </summary>
public static IEnumerable TestCasesDataForTestCaseSourceTest
{
get
{
yield return new TestCaseData( 1, "1" ).Returns( 2 ); // Defines the test data and the expected return
yield return new TestCaseData( 2, "2" ).Returns( 4 );
yield return new TestCaseData( 0, "a" )
.Throws(typeof(ArgumentException)); // Defines the test data and the expected throw exception
}
}
}
/// <summary>
/// TestFixture defines a class of tests
/// </summary>
[TestFixture(), Category("MyTests"), Description("NUnut Cheat Sheet!")]
public class Test
{
/// <summary>
/// TestCaseSource attributes can use static properties to return an array of test data
/// </summary>
public static object[] CaseSourceTestData =
{
new object[] { 1, 1.1m, "2.1" },
new object[] { 2, 2.2m, "4.2" },
new object[] { 3, 3.3m, "6.3" },
};
# region Setup and Tear Down
/// <summary>
/// TestFixtureSetUp called once before any tests have been run in the same TestFixture
/// </summary>
[TestFixtureSetUp] public void FixtureSetUp()
{
// Set up code here.
}
/// <summary>
/// TestFixtureTearDown called once after all tests have been run in the same TestFixture
/// </summary>
[TestFixtureTearDown] public void FixtureTearDown()
{
// Clear up code here.
}
/// <summary>
/// SetsUp is called once before each Test within the same TestFxiture
/// </summary>
[SetUp] public void SetUp()
{
// Set up code here.
// If this throws an exception no Test in the TestFixture are run.
}
/// <summary>
/// TearsDown is called once after each Test within the same TestFixture.
/// </summary>
[TearDown] public void TearDown()
{
// Clear up code here.
// Will not run if no tess are run due to [SetUp] throwing an exception
}
# endregion
/// <summary>
/// ExpectedException defines what exception and how it is configured
/// </summary>
[Test, ExpectedException( typeof(Exception), ExpectedMessage = "Foo", MatchType = MessageMatch.Exact)]
public void ExpectedExceptionAttributeTest()
{
// MessageMatch is an enum of: Contains, Exact, Regex, StartsWith
throw new Exception("Foo");
}
/// <summary>
/// Explicit defines tests which are only run manualy.
/// </summary>
[Test, Explicit("Test has to be run explicitly")]
public void ExplicitAttributeTest()
{
}
/// <summary>
/// Ignore marks tests which are not run even if run manually
/// </summary>
[Test, Ignore("Ignore this test")]
public void IgnoreAttribueTest()
{
}
/// <summary>
/// MaxTimeAttribute defines the max run time in milliseconds before the test is considered as failed but allowed to complete.
/// </summary>
[Test, MaxTimeAttribute(2000)]
public void MaxtimeAttributeTest()
{
}
/// <summary>
/// Timeout defines the max run time in milliseconds before the test is automatically failed.
/// Can be used on TestFixture to set for each contained Test's
/// </summary>
[Test, Timeout(200)]
public void TimeOutTest()
{
}
/// <summary>
///
/// </summary>
[Test, Platform("Mono"), Culture("en-GB")]
public void PlatformAttributeTest()
{
// Can also provide exclusion culture and platform
// Test case is ignored if Platform or Cultrue can not be provided
}
/// <summary>t
/// Property: categorises the test witin the test output XML.
/// </summary>
[Test, Property("PropertyName", "Value")]
public void PropertyAttributeTest()
{}
/// <summary>
/// Custom Property: categorises the test within the test output XML.
/// </summary>
[Test, CustomPropertyAttribute(CustomPropertyValue.One)]
public void CustomPropertyAttributeTest()
{}
#region Parameterized
/// <summary>
/// Combinatorial: The test is run with each combination of Values for each parameter
/// </summary>
[Test, Combinatorial]
public void CombinatorialAttributeTest ([Values(1,2,3)] int a, [Values("a", "b", "c")] string b)
{
// Called 9 times with parameter pairs of: {1,a}, {1,b}, {1,c}, {2,a}, {3,b}....
}
/// <summary>
/// Random: Test can be run with a random value. Random(Min,Max,Count)
/// </summary>
[Test]
public void RandomAttributeTest(
[Random(1, 10, 2)] int value)
{
// Called 2 times with a random integer between 1 and 10
Assert.That(value, Is.InRange(1,10));
}
/// <summary>
/// Sequential: Parameters with values are run in sequence
/// </summary>
[Test, Sequential]
public void SequentialAttributeTest(
[Values(1,2,3)] int x,
[Values("A","B")] string s)
{
// Test runs for parameter pairs {1,A}, {2,B}, {3, null}
}
/// <summary>
/// Range: Parameter is run with a sequence of values incremented. Range(Min,Max,Increment).
/// </summary>
[Test]
public void RangeAttributeTest(
[Range(0.0, 1, 0.5)] decimal value)
{
// Test run for parameters, 0.0, 0.5, 1.0
Assert.That(value, Is.InRange(0m,1m));
}
/// <summary>
/// TestCaseSource: referencing a public property which privides a sequence of test data
/// </summary>
[Test, TestCaseSource("CaseSourceTestData")]
public void CaseSourceTest(int a, decimal b, string c)
{
// Can also specify the class to which the property is found upon.
Assert.That(a + b, Is.EqualTo(Decimal.Parse(c)));
}
/// <summary>
/// TestCaseSource: referncing a class and property which provides a sequence of test data and expected output.
/// </summary>
[Test,TestCaseSource(typeof(TestCaseDataFactory),"TestCasesDataForTestCaseSourceTest")]
public decimal TestCaseSourceTest(int a, string b)
{
int bInt;
if( !int.TryParse(b, out bInt))
throw new ArgumentException(string.Format("Can not parse '{0}' to an integer", b), "b");
return a + bInt;
}
/// <summary>
/// TestCase: provides a test input data and expected result.
/// </summary>
[TestCase(1,1, Result=2)]
[TestCase(2,2, Result=4)]
[TestCase(3,3, Result=6)]
public int TestCaseTest(int a, int b)
{
return( a + b);
}
#endregion
/// <summary>
/// Assertion Based Test
/// </summary>
[Test(), Category("Assertion based testing")]
public void TestAssertions ()
{
// Equality
Assert.AreEqual (true, true);
Assert.AreNotEqual (true, false);
// Identity
Assert.AreSame (string.Empty, string.Empty);
Assert.AreNotSame (new object (), new object ());
Assert.Contains (string.Empty, new List<object> (){string.Empty});
// Condition
Assert.IsTrue (true);
Assert.IsFalse (false);
Assert.IsNull (null);
Assert.IsNaN (Double.NaN);
Assert.IsEmpty (new List<object> ());
Assert.IsEmpty (new List<object> ());
Assert.IsNotEmpty (new List<object> (){1});
Assert.IsNotEmpty ("Foo");
// Comparision
Assert.Greater (Decimal.MaxValue, Decimal.MinValue);
Assert.GreaterOrEqual (Decimal.MinValue, Decimal.MinValue);
Assert.Less (Decimal.MinValue, Decimal.MaxValue);
Assert.LessOrEqual (Decimal.MinValue, Decimal.MinValue);
// Types
Assert.IsInstanceOf<decimal> (decimal.MinValue);
Assert.IsNotInstanceOf<int> (decimal.MinValue);
Assert.IsNotAssignableFrom (typeof(List<Type>), string.Empty); // Equivalent to Type.IsAssignableFrom Method
Assert.IsAssignableFrom (typeof(List<decimal>), new List<decimal> ()); // http://msdn.microsoft.com/en-gb/library/system.type.isassignablefrom.aspx
Assert.IsNotAssignableFrom<List<Type>> (string.Empty);
Assert.IsAssignableFrom<List<decimal>> (new List<decimal> ());
// Exceptions
Assert.Throws (typeof(ArgumentNullException), () => {
throw new ArgumentNullException (); }
);
Assert.Throws<ArgumentNullException> (() => {
throw new ArgumentNullException (); }
);
Assert.DoesNotThrow (() => { });
Assert.Catch (typeof(Exception), () => {
throw new ArgumentNullException (); }
);
Assert.Catch<Exception> (() => { // Similar as Throws but allows any derrived class of the thrown exception
throw new ArgumentNullException (); }
);
// Strings
StringAssert.Contains ("Foo", "MooFooMoo");
StringAssert.StartsWith ("Foo", "FooMoo");
StringAssert.EndsWith ("Moo", "FooMoo");
StringAssert.AreEqualIgnoringCase ("FOO", "foo");
StringAssert.IsMatch ("[0-9]", "1");
// Collections
CollectionAssert.AllItemsAreInstancesOfType (new List<decimal> (){ 0m }, typeof(decimal));
CollectionAssert.AllItemsAreNotNull (new List<decimal> (){ 0m });
CollectionAssert.AllItemsAreUnique (new List<decimal> (){ 0m, 1m });
CollectionAssert.AreEqual (new List<decimal> (){ 0m }, new List<decimal> (){ 0m });
CollectionAssert.AreEquivalent (new List<decimal> (){ 0m, 1m }, new List<decimal> (){ 1m, 0m }); // Same as AreEqual though order does not mater
CollectionAssert.AreNotEqual (new List<decimal> (){ 0m }, new List<decimal> (){ 1m });
CollectionAssert.AreNotEquivalent (new List<decimal> (){ 0m, 1m }, new List<decimal> (){ 1m, 2m }); // Same as AreNotEqual though order does not matter
CollectionAssert.Contains (new List<decimal> (){ 0m, 1m }, 1m);
CollectionAssert.DoesNotContain (new List<decimal> (){ 0m, 1m }, 2m);
CollectionAssert.IsSubsetOf (new List<decimal> (){ 1m }, new List<decimal> (){ 0m, 1m }); // {1} is considered a SubSet of {1,2}
CollectionAssert.IsNotSubsetOf (new List<decimal> (){ 1m, 2m }, new List<decimal> (){ 0m, 1m });
CollectionAssert.IsEmpty (new List<decimal> (){ });
CollectionAssert.IsNotEmpty (new List<decimal> (){ 1m });
CollectionAssert.IsOrdered (new List<decimal> (){ 1m, 2m, 3m });
CollectionAssert.IsOrdered (new List<string> (){ "a", "A", "b"}, StringComparer.CurrentCultureIgnoreCase);
CollectionAssert.IsOrdered (new List<int> (){ 3,2,1}, new ReverseComparer()); // Only supports ICompare and not ICompare<T> as of version 2.6
// File Assert: various ways to compare a stream or file.
FileAssert.AreEqual (new MemoryStream (), new MemoryStream ());
FileAssert.AreEqual (new FileInfo ("MyFile.txt"), new FileInfo ("MyFile.txt"));
FileAssert.AreEqual ("MyFile.txt", "MyFile.txt");
FileAssert.AreNotEqual (new FileInfo ("MyFile.txt"), new FileInfo ("MyFile2.txt"));
FileAssert.AreNotEqual ("MyFile.txt", "MyFile2.txt");
FileAssert.AreNotEqual (new FileStream ("MyFile.txt", FileMode.Open), new FileStream ("MyFile2.txt", FileMode.Open));
// Utilities: will cause the test to stop immediatly and mark the test as:
Assert.Pass ();
Assert.Fail ();
Assert.Ignore ();
Assert.Inconclusive ();
// Defining the failed message
Assert.IsTrue(true, "A failed message here"); // also object[] params can be defined
}
/// <summary>
/// Constraint based testing: Test cases with a fluent design pattern
/// </summary>
[Test()]
[Category("Constraint based testing")]
public void TestConstraints ()
{
// Numerical Equality
Assert.That (1, Is.EqualTo (1));
Assert.That (1, Is.Not.EqualTo (2));
Assert.That (1.1, Is.EqualTo (1.2).Within (0.1)); // Allow a tollerance
Assert.That (1.1, Is.EqualTo (1.01).Within (10).Percent); // Pass tollerance within percent
// Float Equality
Assert.That (20000000000000004.0, Is.EqualTo (20000000000000000.0).Within (1).Ulps); // Pass tollerance with units of last place
// String Equality
Assert.That ("Foo!", Is.EqualTo ("Foo!"));
Assert.That ("Foo!", Is.Not.EqualTo ("FOO!"));
Assert.That ("Foo!", Is.EqualTo ("FOO!").IgnoreCase);
Assert.That (new List<string> (){ "FOO!"}, Is.EqualTo (new List<string> (){ "Foo!"}).IgnoreCase);
// Date, Time and TimeSpan equality
Assert.That (DateTime.Today, Is.EqualTo (DateTime.Today));
Assert.That (DateTime.Now, Is.Not.EqualTo (DateTime.Now));
Assert.That (DateTime.Now, Is.EqualTo (DateTime.Now).Within (TimeSpan.FromSeconds (1))); // Time based pass tollerances
Assert.That (DateTime.Now, Is.EqualTo (DateTime.Now).Within (1).Days);
Assert.That (DateTime.Now, Is.EqualTo (DateTime.Now).Within (1).Hours);
Assert.That (DateTime.Now, Is.EqualTo (DateTime.Now).Within (1).Minutes);
Assert.That (DateTime.Now, Is.EqualTo (DateTime.Now).Within (1).Seconds);
Assert.That (DateTime.Now, Is.EqualTo (DateTime.Now).Within (1).Milliseconds);
// Collection equality
Assert.That (new double[] {1.0,2.0,3.0}, Is.EqualTo (new int[] {1,2,3}));
Assert.That (new double[] {1.0,2.0,3.0}, Is.Not.EqualTo (new int[] {1,2,3, 4}));
Assert.That (new double[] {1.0,2.0,3.0,4.0}, Is.EqualTo (new int[,] {{1,2}, {3,4}}).AsCollection); // Compare data and not collection (flattens a collection of collections)
// Customer Comparer
Assert.That( int.MinValue, Is.EqualTo(int.MaxValue).Using(new WhoCaresComparer()));
// Identity (Same instance of)
Assert.That( string.Empty, Is.SameAs(string.Empty));
Assert.That( new object(), Is.Not.SameAs(new object()));
// Condition
Assert.That( string.Empty, Is.Not.Null);
Assert.That( true, Is.True);
Assert.That( true, Is.Not.False);
Assert.That( double.NaN, Is.NaN);
Assert.That( string.Empty, Is.Empty);
Assert.That( new List<int>(), Is.Empty);
Assert.That( new List<int>(){1,2,3}, Is.Unique);
// Comparision
Assert.That(1, Is.LessThan(2));
Assert.That(1, Is.GreaterThan(0));
Assert.That(1, Is.LessThanOrEqualTo(1));
Assert.That(1, Is.GreaterThanOrEqualTo(1));
Assert.That(1, Is.AtLeast(0)); // Same as GreaterThanOrEqualTo
Assert.That(1, Is.AtMost(2)); // Same as LessThanOrEqualTo
Assert.That(1, Is.InRange(1,2));
// Path: comparision on file path only without comparing the contents.
// All paths are converted to 'canonical' path before comparing; full direct path to file.
Assert.That( "MyFile.txt", Is.SamePath("MyFile.txt"));
Assert.That( "MyFile.txt", Is.SamePath( "MYFILE.TXT" ).IgnoreCase );
Assert.That( "MyFile.txt", Is.SamePath("MyFile.txt").RespectCase);
Assert.That( "/usr/bin", Is.SubPath("/usr")); // directory exists within another
Assert.That( "/usr/bin", Is.SamePathOrUnder("/usr")); // SamePath or SubPath
// Type Constraints
Assert.That(new MemoryStream(), Is.InstanceOf(typeof(Stream))); // Is type or ancestor
Assert.That(new MemoryStream(), Is.TypeOf(typeof(MemoryStream))); // Is type and not ancestor
Assert.That(new object(), Is.AssignableFrom(typeof(MemoryStream))); // Can be assigned from
Assert.That(new MemoryStream(), Is.AssignableTo(typeof(Stream))); // Can be assignable to
Assert.That(new MemoryStream(), Is.InstanceOf<Stream>()); // Is type or ancestor
Assert.That(new MemoryStream(), Is.TypeOf<MemoryStream>()); // Is type and not ancestor
Assert.That(new object(), Is.AssignableFrom<MemoryStream>()); // Can be assigned from
Assert.That(new MemoryStream(), Is.AssignableTo<Stream>()); // Can be assignable to
// String Comparision
Assert.That( "Foo", Is.StringContaining( "o" ) );
Assert.That( "Foo", Is.StringContaining( "O" ).IgnoreCase );
Assert.That( "Foo", Is.StringStarting( "F" ) );
Assert.That( "Foo", Is.StringEnding( "o" ) );
Assert.That( "Foo", Is.StringMatching( "^[F]" ) ); // Regular ecpression match
// Collection Comparison
Assert.That( new List<int>(){1,2,3}, Has.All.GreaterThan(0) );
Assert.That( new List<int>(){1,2,3}, Is.All.GreaterThan(0) );
Assert.That( new List<int>(){1,2,3}, Has.None.GreaterThan(4));
Assert.That( new List<int>(){1,2,3}, Has.Some.GreaterThan(2));
Assert.That( new List<int>(){1,2,3}, Has.Count.EqualTo(3));
Assert.That( new List<int>(){1,2,3}, Is.Unique);
Assert.That( new List<int>(){1,2,3}, Has.Member(1)); // Contains
Assert.That( new List<int>(){1,2,3}, Is.EquivalentTo( new List<int>(){3,2,1})); // Same data without carring about the order
Assert.That( new List<int>(){1,2,}, Is.SubsetOf( new List<int>(){3,2,1})); // All are cotained.
// Property Constraint
Assert.That( new List<int>(), Has.Property("Count").EqualTo(0)); // Checks public property
Assert.That( new List<int>(), Has.Count.EqualTo(0)); // Same as Has.Property("Count").EqualTo(0)
Assert.That( string.Empty, Has.Length.EqualTo(0)); // Same as Has.Property("Length").EqualTo(0)
Assert.That ( new Exception("Foo"), Has.Message.EqualTo("Foo")); // Exception has message
Assert.That ( new Exception("Foo", new ArgumentException("Moo")), // Inner exception is of type and has message
Has.InnerException.InstanceOf<ArgumentException>().And.InnerException.Message.EqualTo("Moo"));
// Throws Constraint
// See also Property constrains for Message and Inner Exception
// Throws.Exception allow AND, Throws.InstanceOf<> is short hand
Assert.That (() => { throw new ArgumentException("Foo"); },
Throws.Exception.InstanceOf<ArgumentException>().And.Message.EqualTo("Foo"));
Assert.That (() => { throw new ArgumentNullException("Foo"); },
Throws.Exception.TypeOf<ArgumentNullException>());
Assert.That (() => { throw new ArgumentNullException("Foo"); },
Throws.InstanceOf<ArgumentNullException>());
Assert.That (() => { }, Throws.Nothing);
Assert.That (() => { throw new Exception("Foo", new ArgumentException("Moo"));},
Throws.Exception.Message.EqualTo("Foo").And.InnerException.InstanceOf<ArgumentException>());
Assert.That (() => { throw new ArgumentException(); }, Throws.ArgumentException);
// Compound Constraints
Assert.That( 2, Is.Not.EqualTo( 1 ));
Assert.That( new List<int>(){ 1, 2, 3 }, Is.All.GreaterThan( 0 ) );
Assert.That( 1, Is.GreaterThan( 0 ).And.LessThan( 2 ) ); // .And amd & are the same
Assert.That( 1, Is.GreaterThan( 0 ) & Is.LessThan( 2 ) );
Assert.That( 1, Is.LessThan( 10 ) | Is.GreaterThan( 0 ) ); // .Or and | are the same
Assert.That( 1, Is.LessThan( 10 ).Or.GreaterThan( 0 ) );
// Delayed
Assert.That(() => { return true;}, Is.True.After(10)); // Passes after x time
Assert.That(() => { return true;}, Is.True.After(10, 10)); // Passes after x time and polling..
// List Mapper
Assert.That(List.Map(new List<string>(){"1", "22", "333"}).Property("Length"), // Allows all elememts in a list to have a condition provided for them
Is.EqualTo(new List<int>(){1,2,3}));
}
}
# region Elements consumed by the tests above
public class WhoCaresComparer : IEqualityComparer<int>
{
public bool Equals(int b1, int b2)
{
return true;
}
public int GetHashCode(int aNumber)
{
return aNumber.GetHashCode();
}
}
public class ReverseComparer : IComparer
{
public int Compare (object a, object b)
{
return ((int)b).CompareTo((int)a);
}
}
public enum CustomPropertyValue
{
One,
Two,
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class CustomPropertyAttribute : PropertyAttribute
{
public CustomPropertyAttribute( CustomPropertyValue value ) : base( "Custom", value.ToString() )
{
}
}
#endregion
}