IMPORTANT: DEPRECATION NOTICE
This documention is for Version 1 of these full .NET Framework libraries and it has been deprecated.
Please see the [Version 2] documentation for the following ChannelAdam .NET Standard libraries.
Overview
The open source ChannelAdam Test Framework Libraries are a set of automated testing libraries to make testing your .NET code easier.
There are currently 3 main libraries:
- The ChannelAdam Test Framework - the common test framework library without a dependency on any other test runner or library
- The ChannelAdam Test Framework for MSTest - containing MSTest-specific implementations of interfaces in the common library
- The ChannelAdam Test Framework for BizTalk - containing functionality
specifically for testing Microsoft BizTalk artifacts.
The ChannelAdam Test Framework Libraries are fully compatible with MSTest and .NET Framework 4.0 and above.
Note: I highly recommend using these libraries with Behaviour-Driven Development practices
and the usage of SpecFlow.
Getting Started
NuGet Package Installation
The easiest way to get started is to install the library that suits your favourite test runner or test library.
Currently however there is only the MSTest implementation…
To install the ChannelAdam.TestFramework.MSTest NuGet package
run the following command in the Package Manager Console:
1PM> Install-Package ChannelAdam.TestFramework.MSTest
Features
Logger
Logging useful information to the output of a test is extremely important.
The ISimpleLogger interface
in the ChannelAdam Core Library provides a very simple interface with a simple Log
method that is intended
for usage in scenarios such writing test output.
The SimpleConsoleLogger class
implements ISimpleLogger
and is a thin wrapper around Console.WriteLine().
Log and then Assert
I cannot emphasise enough how important it is to log useful to the output of a test.
Developers and analysts almost should be able to read the output of a test like a story.
Analysts especially should review the test outputs and be satisfied that the test was implemented correctly - almost as if they performed the test themselves.
Therefore, when an assertion is performed, we want the test output to actually tell us that an assertion is taking place and
provide a information about what is being asserted.
The Log Asserter interface
provides all the usual assertion methods that you are familiar with, and the first parameter of all of the methods is a string
that will be outputted to an ISimpleLogger
(provided in the constructor) before performing the actual assertion.
This LogAssert class
is the MSTest implementation of the Log Asserter
interface.
Test Easy Base Class for Tests
Logging, assertions and testing for exceptions are 3 of some fundamental features common to most automated test suites.
Wouldn’t it be nice to be able to perform that functionality easily and keep your test code to a minimum?
The TestEasy base class for tests
provides those abilities.
This class provides the following helpful properties.
-
ISimpleLogger Logger
- for logging to the test output
-
ILogAsserter LogAssert
- your handy-dandy log asserter
-
ExpectedExceptionDescriptor ExpectedException
- describes the exception that is expected to occur for a specific test case
-
Exception ActualException
- for storing the actual exception that occurred
When the ActualException
property is set, the details are automatically logged to the test output.
TestEasy
also contains the following helpful methods:
-
void Try(Action action)
- performs the given action and catches exceptions into ActualException
-
void Try(Func<Task> action)
- performs the given asynchronous action that returns a Task, waits for it finish, and catches exceptions into ActualException
-
void AssertNoExceptionOccurred()
- asserts that no ActualException
exists/occurred
-
void AssertExpectedException(Type expectedExceptionType)
- asserts that type of the value of ActualException
is the given expected type
-
void AssertExpectedException()
- asserts that the ActualException
is equivalent to that described by the ExpectedException
descriptor.
When the ActualException
is an System.AggregateException
, the assertion will pass if there is at least one inner exception equivalent to the ExpectedException
descriptor.
Expected Exception Descriptor
The ExpectedException
property is implemented by the
ExpectedExceptionDescriptor class.
This class describes the exception that is expected to occur.
There are 2 properties in ExpectedExceptionDescriptor
that are specifically used in the AssertExpectedException()
method:
-
string MessageShouldContainText
- which describes the substring that the ActualException.Message
property should contain
-
Type ExpectedType
- which describes the System.Type
that ActualException
should be.
Either or both of these properties can be set.
When set, the details are automatically logged to the test output.
Moq Test Fixture Base Class for Tests
MoqTestFixture
inherits all the goodies from TestEasy
and also provides a MyMockRepositoy
property to access the Moq MockRepository
.
The default constructor automatically creates a Moq “loose” MockRepository
, but that can be specified in an overload of the constructor.
Text Tester
The TextTester class
is used in tests for asserting whether actual text is similar enough to the given expected text.
Under the covers, it uses the DiffPlex open source library to identify differences.
The TextTester
class has the following properties:
And the following methods:
-
void ArrangeActualText(Assembly assembly, string resourceName)
- to arrange the actual text from an embedded resource in the given assembly
-
void ArrangeActualText(string text)
- to arrange the actual text from the given string
-
void ArrangeExpectedText(Assembly assembly, string resourceName)
- to arrange the expected text from an embedded resource in the given assembly
-
void ArrangeExpectedText(string text)
- to arrange the expected text from the given string
-
virtual void AssertActualTextEqualsExpectedText()
- to assert the actual text against the expected text
-
bool IsEqual()
- determines if the given actual and expected text is equivalent
-
virtual bool IsEqual(string expected, string actual)
- determines if the given actual and expected text is equivalent
Filtering Text Differences
The TextTester
class provides 3 mechanisms for hooking into the
DiffPlex DiffPaneModel
difference result, allowing you to manipulate it before a final decision is made as
to whether or not the actual text is similar enough to the expected text.
- An event that is raised with the differences
1 /// <summary>
2 /// Occurs when a text difference is detected, allowing a listener to filter the differences and
3 /// change the Line[x].Type to ChangeType.UnChanged so that the difference is no longer treated as a difference.
4 /// </summary>
5 /// <remarks>
6 /// This event or the TextDifferenceFilter property can be used for this purpose.
7 /// </remarks>
8 public event EventHandler<TextDifferenceDetectedEventArgs> TextDifferenceDetectedEvent;
- An action delegate method that is called with the differences
1 /// <summary>
2 /// Gets or sets the Action delegate to be invoked when a text difference is detected, allowing differences to be filtered out by
3 /// changing the Line[x].Type to ChangeType.UnChanged - so that a difference is no longer treated as a difference.
4 /// </summary>
5 /// <value>The Action delegate.</value>
6 /// <remarks>
7 /// This property or TextDifferenceDetectedEvent can be used for this purpose.
8 /// </remarks>
9 public Action<DiffPaneModel> TextDifferenceFilter { get; set; }
- A virtual method that allows you to inherit from the tester class and override the differences when they are detected.
1 protected virtual void OnTextDifferenceDetected(DiffPaneModel differences)
For a quick example, please see the Behaviour Specification for the
TextTester class
and the associated
text tester code
XML Tester
The XmlTester class
is used in tests for asserting whether the actual XML is similar enough to the given expected XML.
Under the covers, it uses the XMLUnit.NET open source library to identify differences.
The XMLTester
class has the following properties:
-
XElement ActualXml
-
XElement ExpectedXml
-
Diff Differences
And the following methods:
-
void ArrangeActualXml(Assembly assembly, string resourceName)
- to arrange the actual XML from an embedded resource in the given assembly
-
void ArrangeActualXml(XElement xmlElement)
- to arrange the actual XML from a given XElement
-
void ArrangeActualXml(object valueToSerialise)
- to arrange the actual XML by serialising the given object
-
void ArrangeActualXml(object valueToSerialise, XmlRootAttribute xmlRootAttribute)
- to arrange the actual XML by serialising the given object and applying the given XmlRootAttribute
during the serialisation
-
void ArrangeActualXml(object valueToSerialise, XmlAttributeOverrides xmlAttributeOverrides)
- to arrange the actual XML by serialising the given object and applying the given XmlAttributeOverrides
during the serialisation
-
void ArrangeActualXml(string xmlValue)
- to arrange the actual XML from the given XML string
-
void ArrangeExpectedXml(Assembly assembly, string resourceName)
- to arrange the expected XML from an embedded resource in the given assembly
-
void ArrangeExpectedXml(XElement xmlElement)
- to arrange the expected XML from a given XElement
-
void ArrangeExpectedXml(object valueToSerialise)
- to arrange the expected XML by serialising the given object
-
void ArrangeExpectedXml(object valueToSerialise, XmlRootAttribute xmlRootAttribute)
- to arrange the expected XML by serialising the given object and applying the given XmlRootAttribute
during the serialisation
-
void ArrangeExpectedXml(object valueToSerialise, XmlAttributeOverrides xmlAttributeOverrides)
- to arrange the expected XML by serialising the given object and applying the given XmlAttributeOverrides
during the serialisation
-
void ArrangeExpectedXml(string xmlValue)
- to arrange the expected XML from the given XML string
-
virtual void AssertActualXmlEqualsExpectedXml()
- to assert the actual XML against the expected XML
-
virtual void AssertActualXmlEqualsExpectedXml(IXmlFilter xmlFilter)
- to assert the actual XML against the expected XML, ignoring items listed in the given IXmlFilter
(see below)
-
bool IsEqual()
- determines if the given actual and expected XML is equivalent
-
bool IsEqual(XNode expected, XNode actual)
- determines if the given actual and expected XNode XML is equivalent
-
virtual bool IsEqual(XmlNode expected, XmlNode actual)
- determines if the given actual and expected XmlNode XML is equivalent
Ignoring / Filtering XML Elements
The AssertActualXmlEqualsExpectedXml(IXmlFilter xmlFilter)
override allows you to specify an
IXmlFilter interface
which allows you to specify a list of the local names of XML elements to ignore in comparisons, and/or a list of XPath expressions to ignore in comparisons.
Examples
For a quick example, please see the Behaviour Specification for the
XmlTester class
and the
XML tester code
XML Filter
The XmlFilter class
allows you to specify a list of the local names of XML elements to ignore in comparisons, and/or a list of XPath expressions to ignore in comparisons.
Two constructor methods allow you to easily specify these lists.
-
XmlFilter(IList<string> elementLocalNamesToIgnore)
-
XmlFilter(IList<string> elementLocalNamesToIgnore, IList<string> xpathsToIgnore)
XML Asserter
The XmlAsserter class
provides utility methods for performing assertions on XML values.
It has the following methods:
-
void XPathValueEquals(string description, string xpath, XNode rootElement, string expected)
- to assert that the given XPath of the provided XNode has the given expected string value
-
void XPathValueEquals(string description, string xpath, XNode rootElement, XmlNamespaceManager namespaceManager, string expected)
- uses the provided namespace manager to assert that the given XPath of the provided XNode has the given expected string value
-
void XPathValuesAreEqual(string description, string xpath, XNode expectedElements, XNode actualElements)
- to assert that the value of the XPath in the given actual XNode equals the corresponding value in the given expected XNode
-
void XPathValuesAreEqual(string description, string expectedXpath, XNode expectedElements, string actualXpath, XNode actualElements)
- to assert that the value of the actual XPath in the actual XNode is the same as the value of the expected XPath in the expected XNode
-
void XPathValuesAreEqual(string description, string expectedXpath, XNode expectedElements, XmlNamespaceManager expectedNamespaceManager, string actualXpath, XNode actualElements, XmlNamespaceManager actualNamespaceManager)
- to assert that the value of the actual XPath in the actual XNode is the same as the value of the expected XPath in the expected XNode, using the provided XML namespace managers
-
void AreEqual(XElement expectedXml, XElement actualXml)
- to assert that the given expected XElement is equivalent to the actual XElement
-
void AreEqual(XElement expectedXml, XElement actualXml, IXmlFilter xmlFilter)
- to assert that the given expected XElement is equivalent to the actual XElement - using the given IXmlFilter
Mapping Testers
There are 4 map tester classes to be used depending on the type of input and output of your map:
The MappingFromXmlToXmlTester class
has the following method overrides for arranging the input XML.
-
void ArrangeInputXml(Assembly assembly, string resourceName)
- to arrange the input XML from an embedded resource in the given assembly
-
void ArrangeInputXml(XElement xmlElement)
- to arrange the input XML from a given XElement
-
void ArrangeInputXml(object valueToSerialise)
- to arrange the input XML by serialising the given object
-
void ArrangeInputXml(object valueToSerialise, XmlRootAttribute xmlRootAttribute)
- to arrange the input XML by serialising the given object and applying the given XmlRootAttribute
during the serialisation
-
void ArrangeInputXml(object valueToSerialise, XmlAttributeOverrides xmlAttributeOverrides)
- to arrange the input XML by serialising the given object and applying the given XmlAttributeOverrides
during the serialisation
-
void ArrangeInputXml(string xmlValue)
- to arrange the input XML from the given XML string
-
void ArrangeExpectedOutputXml(Assembly assembly, string resourceName)
- to arrange the expected output XML from an embedded resource in the given assembly
-
void ArrangeExpectedOutputXml(XElement xmlElement)
- to arrange the expected output XML from a given XElement
-
void ArrangeExpectedOutputXml(object valueToSerialise)
- to arrange the expected output XML by serialising the given object
-
void ArrangeExpectedOutputXml(object valueToSerialise, XmlRootAttribute xmlRootAttribute)
- to arrange the expected output XML by serialising the given object and applying the given XmlRootAttribute
during the serialisation
-
void ArrangeExpectedOutputXml(object valueToSerialise, XmlAttributeOverrides xmlAttributeOverrides)
- to arrange the expected output XML by serialising the given object and applying the given XmlAttributeOverrides
during the serialisation
-
void ArrangeExpectedOutputXml(string xmlValue)
- to arrange the expected output XML from the given XML string
Input can be arranged from an embedded resource, XElement, object that is XML serialisable (for which you can also override the root XML namespace when serialised) or simply a string.
This same pattern is followed for arranging the expected output of the map, and for arranging the contents of flat files with the other map tester classes.
Assert - Compare the Actual Output Against the Expected Output
The MappingFromXmlToXmlTester class
has the following method overrides for asserting the actual output from the map against the expected output that was arranged.
All the comparison and logging and formatting of any differences is done for you. Easy!
Ignoring / Filtering XML Elements
The AssertActualOutputXmlEqualsExpectedOutputXml(IXmlFilter xmlFilter)
override allows you to specify an
IXmlFilter
which allows you to specify a list of the local names of XML elements to ignore in comparisons, and/or a list of XPath expressions to ignore in comparisons.
Two constructor methods on XmlFilter
allow you to easily specify these lists.
-
XmlFilter(IList<string> elementLocalNamesToIgnore)
-
XmlFilter(IList<string> elementLocalNamesToIgnore, IList<string> xpathsToIgnore)
Ignoring / Filtering Flat File Differences
Ignoring differences in flat files is a little more tricky, but not too difficult.
The ChannelAdam library uses the DiffPlex library for performing text differences.
3 mechanisms on the flat file tester classes are provided for hooking into the DiffPaneModel
difference result and manipulating it before a final decision is made as
to whether or not the actual output is similar enough to the expected output.
- An event that is raised with the differences
1 /// <summary>
2 /// Occurs when a text difference is detected, allowing a listener to filter the differences and
3 /// change the Line[x].Type to ChangeType.UnChanged so that the difference is no longer treated as a difference.
4 /// </summary>
5 /// <remarks>
6 /// This event or the TextDifferenceFilter property can be used for this purpose.
7 /// </remarks>
8 public event EventHandler<TextDifferenceDetectedEventArgs> TextDifferenceDetectedEvent;
- An action delegate method that is called with the differences
1 /// <summary>
2 /// Gets or sets the Action delegate to be invoked when a text difference is detected, allowing differences to be filtered out by
3 /// changing the Line[x].Type to ChangeType.UnChanged - so that a difference is no longer treated as a difference.
4 /// </summary>
5 /// <value>The Action delegate.</value>
6 /// <remarks>
7 /// This property or TextDifferenceDetectedEvent can be used for this purpose.
8 /// </remarks>
9 public Action<DiffPaneModel> TextDifferenceFilter { get; set; }
- A virtual method that allows you to inherit from the tester class and override the differences when they are detected.
1 protected virtual void OnTextDifferenceDetected(DiffPaneModel differences)