NMock Constraints
NMock constraints allow you to run a validation against a parameter that is passed to your NMock object's method during an NUnit test. I want to share a custom NMock constraint I've written. With this constraint you can write an expectation that compares an expected XML document and the actual XML document. The constraint is called IsEquivalentXml. The constraint class uses a class library written by Microsoft called XmlDiffPatch to do the actual xml comparison.
Some tests that use the new constraint are shown below:
The ClassUnderTest code is shown below:
Some tests that use the new constraint are shown below:
1: [Test]
2: public void MyTest1()
3: {
4: string expectedXml = "<Order></Order>";
5: string actualXml = "<Order></Order>";
6:
7: DynamicMock mockObject = new DynamicMock(typeof(IOrderManager));
8: mockObject.Expect("SubmitOrder", new IsEquivalentXml(expectedXml));
9: ClassUnderTest classUnderTest =
10: new ClassUnderTest((IOrderManager)mockObject.MockInstance);
11: classUnderTest.DoSometing(actualXml);
12: mockObject.Verify();
13: }
1: [Test]
2: public void MyTest2()
3: {
4: string expectedXml = "<Order/>";
5: string actualXml = "<Order></Order>";
6:
7: DynamicMock mockObject = new DynamicMock(typeof(IOrderManager));
8: mockObject.Expect("SubmitOrder", new IsEquivalentXml(expectedXml));
9: ClassUnderTest classUnderTest =
10: new ClassUnderTest((IOrderManager)mockObject.MockInstance);
11: classUnderTest.DoSometing(actualXml);
12: mockObject.Verify();
13: }
1: [Test]
2: public void MyTest3()
3: {
4: string expectedXml = @"<Order id=""123""></Order>";
5: string actualXml = "<Order id='123'></Order>";
6:
7: DynamicMock mockObject = new DynamicMock(typeof(IOrderManager));
8: mockObject.Expect("SubmitOrder", new IsEquivalentXml(expectedXml));
9: ClassUnderTest classUnderTest =
10: new ClassUnderTest((IOrderManager)mockObject.MockInstance);
11: classUnderTest.DoSometing(actualXml);
12: mockObject.Verify();
13: }
1: [Test]
2: public void MyTest10()
3: {
4: string expectedXml = @"<Order>abc123</Order>";
5: string actualXml = "<Order> abc123 </Order>";
6:
7: DynamicMock mockObject = new DynamicMock(typeof(IOrderManager));
8: mockObject.Expect("SubmitOrder",
9: new IsEquivalentXml(expectedXml, XmlDiffOptions.IgnoreWhitespace));
10: ClassUnderTest classUnderTest =
11: new ClassUnderTest((IOrderManager)mockObject.MockInstance);
12: classUnderTest.DoSometing(actualXml);
13: mockObject.Verify();
14: }
The ClassUnderTest code is shown below:
1: using System;
2:
3: namespace CustomNMockConstraintsClassLibrary
4: {
5: public class ClassUnderTest
6: {
7: IOrderManager _orderManager;
8:
9: public ClassUnderTest(IOrderManager orderManager)
10: {
11: this._orderManager = orderManager;
12: }
13:
14: public void DoSometing(string orderXml)
15: {
16: this._orderManager.SubmitOrder(orderXml);
17: }
18: }
19: }
The actual Constraint class is shown below. Notice that I inherit from the NMock BaseConstraint class instead of the IConstraint interface. BaseConstraint is an abstract class that already implements the IConstraint interface.
1: using System;
2: using System.IO;
3: using System.Xml;
4:
5: using NMock;
6: using NMock.Constraints;
7:
8: using Microsoft.XmlDiffPatch;
9:
10: namespace CustomNMockConstraintsClassLibrary
11: {
12: public class IsEquivalentXml : BaseConstraint
13: {
14: private string _expectedXml = string.Empty;
15: private XmlDiff _xmlDiff = new XmlDiff();
16:
17: public IsEquivalentXml(string xml) : this(xml, XmlDiffOptions.None)
18: {
19: }
20:
21: public IsEquivalentXml(string expectedXml, XmlDiffOptions options)
22: {
23: _expectedXml = expectedXml;
24: _xmlDiff.Options = options;
25: }
26:
27: public override bool Eval(object val)
28: {
29: string actualXml = (string)ExtractActualValue(val);
30: return AreEqual(_expectedXml, actualXml);
31: }
32:
33: public override string Message
34: {
35: get { return "<" + _expectedXml + ">"; }
36: }
37:
38: private bool AreEqual(string expectedXml, string actualXml)
39: {
40: bool areEqual = false;
41:
42: try
43: {
44: areEqual = _xmlDiff.Compare(
45: new XmlTextReader(new StringReader(expectedXml)),
46: new XmlTextReader(new StringReader(actualXml)));
47: }
48: catch(Exception e)
49: {
50: _expectedXml += "\n" + e.ToString();
51: }
52:
53: return areEqual;
54: }
55: }
56: }