NUnit Constraints Example – a Simple Custom Constraint

Are you short of an NUnit Assertion? You have some code for a test, but you really want it in NUnit constraint form so you can use it like any other test. They are easy to write. Here's an example which wraps a function you already wrote as a Constraint:

public class EqualsByValueConstraint : Constraint
{
	private readonly object expected;
	private CompareResult compareResult;

	public EqualsByValueConstraint(object expected)
	{
		this.expected = expected;
	}

	public override bool Matches(object actual)
	{
		this.actual = actual;
		compareResult = EqualsByValueOrFailureReason(actual, expected);
		return compareResult;
	}

	public override void WriteDescriptionTo(MessageWriter writer)
	{
		writer.WriteExpectedValue(this.expected);
	}
	public override void WriteActualValueTo(MessageWriter writer)
	{
		base.WriteActualValueTo(writer);
		writer.WriteLine();
		writer.WriteMessageLine("Compare Result " + compareResult);
	}
}
public class CompareResult
{
	public bool IsPass {get;set;}
	public string FailureDescription {get; set;}
}

If your function is just a boolean, then you could remove the CompareResult class. The drawback being that your failure message will only say 'failed' rather than give an explanation of the failure. In that case, you might just as well not use the constraint and use the Assert.That(bool, message) overload.

A Very Small Editable PDF for Testing

A Small PDF

Ever wanted a small PDF file, or to tweak your own PDF for testing? Below is a very small PDF which you can paste into a text editor and save as MySmallPdf.PDF.
Two things are easy to edit:

  • The page size. Look for the line /MediaBox [0 0 612 144]. Leave the first (0,0) pair and edit the (612,144) to be (width of page,height of page) in 1/72ths of an inch.
  • One line of text. Look for the line (This is a small text editable pdf) Tj and replace the text with your own.

This is particularly helpful if you are testing http://itextpdf.com/ or itextsharp or some other PDF generator or API, and you want a couple of small identifiable test files to play with.

The Editable PDF

%PDF-1.4
1 0 obj
<< /Type /Catalog
/Outlines 2 0 R
/Pages 3 0 R
>>
endobj
2 0 obj
<< /Type /Outlines
/Count 0
>>
endobj
3 0 obj
<< /Type /Pages
/Kids [4 0 R]
/Count 1
>>
endobj
4 0 obj
<< /Type /Page
/Parent 3 0 R
/MediaBox [0 0 612 144]
/Contents 5 0 R
/Resources << /ProcSet 6 0 R
/Font << /F1 7 0 R >>
>>
>>
endobj
5 0 obj
<< /Length 73 >>
stream
BT
/F1 24 Tf
100 100 Td
(This is a small text editable pdf) Tj
ET
endstream
endobj
6 0 obj
[/PDF /Text]
endobj
7 0 obj
<< /Type /Font
/Subtype /Type1
/Name /F1
/BaseFont /Helvetica
/Encoding /MacRomanEncoding
>>
endobj
xref
0 8
0000000000 65535 f
0000000009 00000 n
0000000074 00000 n
0000000120 00000 n
0000000179 00000 n
0000000364 00000 n
0000000466 00000 n
0000000496 00000 n
trailer
<< /Size 8
/Root 1 0 R
>>
startxref
625
%%EOF

The PDF ISO32000 standard

The PDF reference is available for free from Adobe at http://www.adobe.com/content/dotcom/en/devnet/pdf/pdf_reference.html The one you want is the copy of the ISO reference at http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf

Sending large byte[] of binary data through WCF – a simple approach

You can send large streams of data through WCF in two ways: by streaming or by buffer. How to enable streaming is discussed here but has the significant restriction that if you stream, you can only have one (yes, 1) parameter into and out of the service. If your goal is just to pass largish objects such as a spreadsheet or a PDF as part of a service operation this could be a significant hurdle to code around.

"By buffer" means that your large data can be handled with no special treatment at all: it is sent, read into memory (the buffer), and processed just like small messages are. You must understand that buffering means the whole message is buffered; As of early 21st century, that is fine on most servers for multi-megabyte data, but maybe not fine for gigabytes of data.

The simple way to handles megabyte messages is to create a binding Configuration with 2 or 3 parameters increased:

  &lt;system.serviceModel&gt;
    &lt;bindings&gt;
      &lt;basicHttpBinding&gt;
        &lt;binding name="basicHttpFor2MBMessage" maxBufferSize="2097152" maxReceivedMessageSize="2097152"&gt;
          &lt;readerQuotas maxArrayLength="2097000" /&gt;
        &lt;/binding&gt;
      &lt;/basicHttpBinding&gt;
    &lt;/bindings&gt;

and have your service endpoint use it:

&lt;endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpFor2MBMessage" contract="yourContractName&gt;

Voila. You can now send a 2MB large array through SOAP to WCF.

If your large array is binary data, you declare it in your service classes as byte[], which is why you need the maxArrayLength setting. If you are creating test messages by hand or in a testing tool, you also need to know how to represent binary data in a SOAP message.
The usual answer is, use base64 encoding and it should just work, thus:

&lt;soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dat="http://MyServiceName"&gt;
   &lt;soapenv:Header/&gt;
   &lt;soapenv:Body&gt;
      &lt;dat:Save&gt;
         &lt;dat:Id&gt;111&lt;/dat:applicantId&gt;
         &lt;dat:Pdf&gt;JVBE ... &lt;i&gt;base64 encoded string&lt;/i&gt; .... JUVPRgo=&lt;/dat:contractPdf&gt;
      &lt;/dat:Save&gt;
   &lt;/soapenv:Body&gt;
&lt;/soapenv:Envelope&gt;

Caveats

Security

The WCF default small buffer and message sizes are a guard against DoS attacks so if your service is publicly visible this would leave it less well guarded.

Performance

How fast does your service process large requests?

If (Expected Peak Requests Per Minute) * (Seconds to Process a Request) is bigger than 60 (Seconds in a Minute) then you need more horsepower.

How much memory do you have?

If (Size of Message * Requests per Hour) - (Speed at which WCF frees up an hour's worth of used buffers) is bigger than your available memory then you'll fall over. Alas there is no simple setting for 'Speed at which WCF frees up an hour's worth of used buffers' so that calculation is a problem for another blog post. If you might have a problem, you can use PerfMon to watch memory behaviour during a stress test.

Moq Mocking Indexer Properties

Mocking an indexer property with Moq is nearly but not quite straightforward. SetUpProperty() doesn't work but if you only need to moq write/read to one or two keys or you can use this code from a stackoverflow post by seanlinmt for each key:

httpContext.SetupSet(x => x.Session["key"] = It.IsAny<object>())
        .Callback((string name, object value) =>
        {
           httpContext.SetupGet(x => x.Session[name]).Returns(value);
        });

The missing functionality is that you have to setup for each specific key you are going to access. You can't do this to setup all in one:

httpContext.SetupSet(x => x.Session[ /**/ It.IsAny<string>() /**/ ] 
    = It.IsAny<object>()). ....

If you're mocking out SessionState or ApplicationState you may want to mock multiple keys even for a single test fixture, but don't want dozens of lines of setup code for each key you use.

You can at least abbreviate by shipping out the setup to an extension method so you can do this:

mockSessionStateBase.SetUpIndexerForKeys("a", "b", "c");

Like this:

public static class MoqStateDictionaryExtension
{
    private static Dictionary<Mock, Dictionary<string, object>> FakeStateDictionaries= new Dictionary<Mock, Dictionary<string, object>>();

    public static void SetUpIndexerForKeys(this Mock<HttpApplicationStateBase> @this, params string[] keys)
    {
        EnsureDictionary(@this);
        foreach (var key in keys)
        {
            string key1 = key;
            @this.SetupSet(
                    x => x[key1] = It.IsAny<object>()
                )
                .Callback<string, object>(
                    (name, val) =>
                    {
                        FakeStateDictionaries[@this][name] = val;
                        @this.SetupGet(x => x[name]).Returns(FakeStateDictionaries[@this][name]);
                    }
                );
        }
    }

    public static void SetUpIndexerForKeys(this Mock<HttpSessionStateBase> @this, params string[] keys)
    {
        EnsureDictionary(@this);
        foreach (var key in keys)
        {
            string key1 = key;
            @this.SetupSet(
                    x => x[key1] = It.IsAny<object>()
                )
                .Callback<string, object>(
                    (name, val) =>
                    {
                        FakeStateDictionaries[@this][name] = val;
                        @this.SetupGet(x => x[name]).Returns(FakeStateDictionaries[@this][name]);
                    }
                );
        }
    }

    private static void EnsureDictionary(Mock mock)
    {
        if (!FakeStateDictionaries.ContainsKey(mock)) { FakeStateDictionaries[mock] = new Dictionary<string, object>(); }
    }
    public static void RemoveDictionary(Mock mock)
    {
        if (FakeStateDictionaries.ContainsKey(mock)) { FakeStateDictionaries.Remove(mock); }
    }
    public static void RemoveDictionaries()
    {
        FakeStateDictionaries = new Dictionary<Mock, Dictionary<string, object>>();
    }
}

Used like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Moq;
using NUnit.Framework;

namespace MockingIndexersWithMoq
{
    [TestFixture]
    public class ApplicationWrapperTests
    {
        private Mock<HttpApplicationStateBase> mockApplication;
        private HttpApplicationStateBase exampleUsage;

        [SetUp]
        public void SetUp()
        {
            mockApplication = new Mock<HttpApplicationStateBase>();
            exampleUsage = mockApplication.Object;
        }

        [TearDown]
        public void ClearFakeStateDictionaries()
        {
            MoqStateDictionaryExtension.RemoveDictionary(mockApplication);
        }

        [Test]
        public void TestWhichReliesOnMockedIndexer()
        {
            mockApplication.SetUpIndexerForKeys("a", "b", "c");

            exampleUsage["a"] = 1;
            exampleUsage["a"].ShouldEqual(1);
            exampleUsage["a"] = 2;
            exampleUsage["a"].ShouldEqual(2);
            exampleUsage["b"] = 1;
            exampleUsage["b"].ShouldEqual(1);
            exampleUsage["c"].ShouldBeNull();
            exampleUsage["d"].ShouldBeNull();
            exampleUsage["e"].ShouldBeNull();
        }
    }
}