Coding

What’s New in CompositionTests 2.0

Download the latest version of CompositionTests from nuget.org!

ApprovalTests 3.0

Updated the dependency on ApprovalTests to 3.0.01. Thanks to the new version updating policy for ApprovalTests, CompositionTests should remain forward compatible with future versions of ApprovalTests, unless there are breaking changes in the API.

New version policy

Following LLewellyn’s lead with ApprovalTests, I am adopting a JSON.NET-style version update policy. Adopting this policy will enable me to sign CompositionTests in the future without creating forward-compatibility problems for anyone else. For now, the package remains unsigned because its other dependency, the MEFX Diagnostic Library is unsigned. I’ll have to decide if I’m willing to do anything about that before I can consider a signed version of CompositionTests.

The impact is that the CompositionTests AssemblyVersion will stay at 2.0.0 from now on. The real version can be found by looking at AssemblyFileVersion, or by looking at the nuget package version, which will be 2.0.1 for this release.

Common Language Specification Compliance

The CompositionTests library now declares itself CLS compliant. However, MEFX.Core does not make the same declaration, so certain methods that interact with the core are individually marked non-compliant. I don’t think that MEFX.Core uses anything non-compliant, the library is simply missing the declaration of compliance. I don’t think Microsoft has plans to provide any more updates to this piece, so I’ll have to decide that I’m willing to modify and maintain a fork of MEFX.Core before I can do anything about that missing attribute.

Removed Obsolete Methods

Methods and types marked with the ObsoleteAttribute in the 1.0 time-frame have been removed in order to clean up the interface in 2.0. You must now migrate to Verify* and MefComposition if you wish to use new versions of the library.

Testing

What’s New in CompositionTests 1.3

CompositionTestsv.1.3.0 (640x640)I hope you are all as excited as I am about the latest ApprovalTests release, 2.0.  This release polishes some rough edges, and adds some exciting new test scenarios.  Check out Llewellyn’s release notes for details.  I’ve been experimenting with CompositionTests 1.3 for a month or so, and now that ApprovalTests has released, I’m releasing 1.3 to go with it.  Other than versioning compatibility, CompositionTests 1.3 doesn’t have any specific dependencies on ApprovalTests 2.0, but it seemed like a good time to release.  Enjoy.

Generic VerifyCatalog Implementation

CompositionTests 1.2 introduced customized Verify*Catalog convenience methods that automatically provide scrubbers that make sense with each catalog type. Although this worked fine, using the convenience methods meant that you needed to make an extra change to your test if you decided to change the catalog type… not very convenient!

The new VerifyCatalog<T> method addresses this shortcoming. The new method will take any catalog descended from ComposablePartCatalog and attempt to find an appropriate Verify*Catalog implementation. When the method cannot find an appropriate implementation, the default is to use VerifyCompositionInfo with no scrubbers.

ApprovalTests 2.0

This version of CompositionTests is built against ApprovalTests 2.0. The CompositionTests 1.2.0 NuGet package incorrectly specified the ApprovalTests dependency as x >= 1.9. Because the ApprovalTest assemblies are signed, dependent assemblies (like CompositionTests) will only load the ApprovalTests assembly which they are built against, so “greater than or equal to” should have been “exactly equal to”. The package for CompositionTests 1.3.0 correctly specifies the dependency as x == 2.0.

If CompostionTests stopped working for you after upgrading to ApprovalTests 2.0, this release should fix that for you.

Reminder

Remember DiscoverParts and Composition are obsolete and will be removed in a future release. Please migrate to Verify* and MefComposition.

Go Get It

As usual you can get the bits from github or NuGet!

http://www.compositiontests.com/

https://nuget.org/packages/CompositionTests

Presentations

From "MEF, WTF?!" to "MEF, FTW!"

In addition to my talk on CoffeeScript at SoCalCodeCamp I also reprised my talk on testing and debugging MEF. I didn’t record this session at UCSD but if you missed it, you can watch a recording of the “premiere” at CSU Fullerton. While I covered a lot of the same ground at UCSD, I did revise the slides and rewrote the sample code from scratch. The biggest difference is that at UCSD I introduced CompositionTests at the end of the talk, which I hope lowers the barrier of entry for beginners.

This post should be short because I’ve already written a few posts on this topic. However, if you attended the session and are here looking for additional information, here’s a list of resources:

Since I don’t have a video, here’s a picture of me standing in front of a Pizza Factory.  See, it’s more that just a lame example from a design patterns book.

WP_000324

A Few Comments on the Sample Code

As I mentioned I rewrote the code. Mostly because the old code was way too complicated. For some reason I was obsessed with using DirectoryCatalogs for everything during the first six months of my career with MEF. In the last six months I’ve come to appreciate the other catalogs, especially while refactoring and certainly for demos. This helped simplify the code a great deal.

Having the benefit of giving the talk before, I knew that I didn’t have time to cover all the failure scenarios I programmed into the original demo. I think I had about 8 different scenarios in the original PizzaStore, and in reality there is only time to demo about two. So, while rewriting the code, I only setup two scenarios, one failure that doesn’t throw an exception, and one that does.

To demonstrate the difference between .NET 4 and 4.5, I used a separate solution. The first time around I copied the solution folder, renamed it, changed references and I was rockin’ and rollin’. This worked well enough to Demo, but the truth was that only one line of code needed to change between .NET 4 and 4.5. This time around the projects share the same files using the “Add As Link” option in Visual Studio.

If you want to poke around the code, you should know that the “Program” project does almost nothing. It holds part definitions that the “Demo” project can play with. The Program class, while it does nothing useful, does show an example of my preferred way to share ExportProviders and ComposablePartCatalogs with test code.

Over in the Demo project we use the TypeCatalog instances to control whether the composition succeeds or fails. We also have an example of implementing a composition test by hand, which includes some really ugly brute force formatting necessary to ensure that the parts are listed in the same order every time. Finally, we have an example of composition test using my own CompositionTests library, which not only removes the burden of writing broiler plate code, but handles the ordering for you.

Coding, Testing

When is the ExportProvider Interesting?

Recently, when writing about the CompositionTests API (here) I wrote that our test should focus on the interesting part of the composition and that most of the time the catalog is the only interesting item.  Later I wrote that there were other scenarios where the ExportProvider was also interesting and when I wrote that I was thinking of custom ExportProvider implementations.  Just Google “mef custom exportprovider” and you will find a wealth of articles written by people who created their own ExportProviders to adapt MEF for their specific needs.  I think I even built one back when I first started out with MEF.

But lets say you haven’t needed or wanted to roll your own ExportProvider.  Does trusty old CompositionContainer ever effect composition?  Can it ever be interesting enough to motivate you to use VerifyCompositionInfo?

A Simple Mailer

Here’s an example of when you might want to use VerifyCompositionInfo because the CompositionContainer is interesting.  Say you are working on an application that wants to send emails. You might start with a little mail sender like this:

[Export(typeof(ISendMail))]
public class BasicMailSender : ISendMail
{
    [ImportingConstructor]
    public BasicMailSender(
        SmtpHost host,
        Port port)
    {
        this.port = port;
        this.host = host;
    }

    public void SendMessage(MailMessage message)
    {
        // ...
    }
}

You have read the CompositionTests readme, and written a simple Program class that allows you to share your ComposablePartCatalog (in this case a TypeCatalog) with your test.

public class Program
{
    static Program()
    {
        Catalog = new TypeCatalog(typeof(BasicMailSender));
        Host = new CompositionContainer(Catalog);
    }

    public static TypeCatalog Catalog { get; private set; }

    public static CompositionContainer Host { get; private set; }

    public static void Main(string[] args)
    {
    }
}

And written a test.

using ApprovalTests.Reporters;
using CompositionTests;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MailApp.Tests
{
    [TestClass]
    [UseReporter(typeof(DiffReporter))]
    public class CompositionTest
    {
        [TestMethod]
        public void VerifyComposition()
        {
            MefComposition.VerifyTypeCatalog(Program.Catalog);
        }
    }
}

Given our current setup, we would expect an unhappy composition, shown below.

[Part] MailApp.BasicMailSender from: TypeCatalog (Types='MailApp.BasicMailSender').
  [Primary Rejection]
  [Export] MailApp.BasicMailSender (ContractName="MailApp.BasicMailSender")
  [Import] MailApp.BasicMailSender..ctor (Parameter="host", ContractName="MailApp.SmtpHost")
    [Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint: 
    ContractName    MailApp.SmtpHost
    RequiredTypeIdentity    MailApp.SmtpHost
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition)
   at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)
  [Import] MailApp.BasicMailSender..ctor (Parameter="port", ContractName="MailApp.Port")
    [Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint: 
    ContractName    MailApp.Port
    RequiredTypeIdentity    MailApp.Port
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition)
   at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)

So we need to provide SmtpHost and Port implementations. The decision on the Port implementation is easy. While we might want to use a non-default Port during testing, we feel pretty safe determining that we want to use the default SMTP port (25) in production. So we can whip up a DefaultPort implementation and export it.

[Export(typeof(Port))]
public class DefaultPort : Port
{
    public DefaultPort() :
        base(25)
    {
    }
}

Everything works as expected if we update our TypeCatalog with this new type.

static Program()
{
    Catalog = new TypeCatalog(typeof(BasicMailSender), typeof(DefaultPort));
    Host = new CompositionContainer(Catalog);
}

And now the test produces this result:

[Part] MailApp.BasicMailSender from: TypeCatalog (Types='MailApp.BasicMailSender, MailApp.DefaultPort').
  [Primary Rejection]
  [Export] MailApp.BasicMailSender (ContractName="MailApp.BasicMailSender")
  [Import] MailApp.BasicMailSender..ctor (Parameter="host", ContractName="MailApp.SmtpHost")
    [Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint: 
    ContractName    MailApp.SmtpHost
    RequiredTypeIdentity    MailApp.SmtpHost
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition)
   at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)
  [Import] MailApp.BasicMailSender..ctor (Parameter="port", ContractName="MailApp.Port")
    [SatisfiedBy] MailApp.DefaultPort (ContractName="MailApp.Port") from: MailApp.DefaultPort from: TypeCatalog (Types='MailApp.BasicMailSender, MailApp.DefaultPort').

[Part] MailApp.DefaultPort from: TypeCatalog (Types='MailApp.BasicMailSender, MailApp.DefaultPort').
  [Export] MailApp.DefaultPort (ContractName="MailApp.Port")

The Port is now satisfied, but SmtpHost is trickier. While the default port for SMTP is defined by standard, there is no such thing as a default server. Now, I would note that one option is to simply approve this result. There is no rule that says you can only approve a CompositionTest when it has no exceptions. The fact that SmtpHost can’t be satisfied could just mean that this part must be provided by a third-party at deployment time. However, there are two reasons why I’ll try to satisfy all of the parts in this test.

  • Ignoring exceptions is like ignoring warnings. When there are only a few you can say to yourself, “Well, that one is there for a reason, and I understand why.” But when the number of warnings/exceptions grow, the signal to noise ratio rises and eventually obscures real errors.
  • If I don’t try to satisfy the part, I won’t be able to show you a scenario where the ExportProvider is interesting.

Lets say that we have a SmtpHost in our test project that we use for development, it points at the localhost. When making these kind of test collaborators I usually nest the Testing class inside the test it supports.

[TestClass]
[UseReporter(typeof(DiffReporter))]
public class CompositionTest
{
    [TestMethod]
    public void VerifyComposition()
    {
        MefComposition.VerifyTypeCatalog(Program.Catalog);
    }

    [Export(typeof(SmtpHost))]
    public class TestingSmtpHost : SmtpHost
    {
        public TestingSmtpHost()
            : base("localhost")
        {
        }
    }
}

It would be nice to use this part when verifying composition, but since it is in our test class, our production code can’t see it. One way around this is to add an instance to our CompositionContainer using a CompositionBatch. We’ll need to add a method, Program.AddInstance, to allow this.

public class Program
{
    static Program()
    {
        Catalog = new TypeCatalog(typeof(BasicMailSender), typeof(DefaultPort));
        Host = new CompositionContainer(Catalog);
    }

    public static TypeCatalog Catalog { get; private set; }

    public static CompositionContainer Host { get; private set; }

    public static void AddInstance(object part)
    {
        var batch = new CompositionBatch();
        batch.AddPart(part);
        Host.Compose(batch);
    }

    // ...
}

Now we can add a class constructor to our test, so that Program is only manipulated once during the course of the test.

[TestClass]
[UseReporter(typeof(DiffReporter))]
public class CompositionTest
{
    static CompositionTest()
    {
        Program.AddInstance(new TestingSmtpHost());
    }

Note that you can’t just throw any object into the method and expect it to compose, it has to be an attributed MEF part. Ok, now we might expect our test result to show a happy composition, but the BasicMailSender still fails to compose.

[Import] MailApp.BasicMailSender..ctor (Parameter="host", ContractName="MailApp.SmtpHost")
  [Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint: 
    ContractName    MailApp.SmtpHost
    RequiredTypeIdentity    MailApp.SmtpHost

What’s up with that? Look closely at the AddInstance method. Nowhere in that method do we manipulate the Catalog.  When we use CompositionBatch, we are adding part directly to the CompositionContainer–outside the catalog. So, our ExportProvider (in this case just a plain old CompositionContainer) is suddenly interesting. Without it, there is no way for the CompositionInfo used by CompositionTests to know about the instance of TestingSmtpHost that we added.

Lets rewrite our test to use an overload of VerifyCompositionInfo so that we can pass in the ExportProvider.

[TestMethod]
public void VerifyComposition()
{
    MefComposition.VerifyCompositionInfo(Program.Catalog, Program.Host);
}

And now our composition is happy.

[Part] MailApp.BasicMailSender from: TypeCatalog (Types='MailApp.BasicMailSender, MailApp.DefaultPort').
  [Export] MailApp.BasicMailSender (ContractName="MailApp.BasicMailSender")
  [Import] MailApp.BasicMailSender..ctor (Parameter="host", ContractName="MailApp.SmtpHost")
    [SatisfiedBy] MailApp.Tests.CompositionTest+TestingSmtpHost (ContractName="MailApp.SmtpHost") from: MailApp.Tests.CompositionTest+TestingSmtpHost
  [Import] MailApp.BasicMailSender..ctor (Parameter="port", ContractName="MailApp.Port")
    [SatisfiedBy] MailApp.DefaultPort (ContractName="MailApp.Port") from: MailApp.DefaultPort from: TypeCatalog (Types='MailApp.BasicMailSender, MailApp.DefaultPort').

[Part] MailApp.DefaultPort from: TypeCatalog (Types='MailApp.BasicMailSender, MailApp.DefaultPort').
  [Export] MailApp.DefaultPort (ContractName="MailApp.Port")

Notice that while the TestingSmtpHost satisfies the host parameter on the BasicMailSender constructor, its “from” tag doesn’t indicate that it comes from a catalog (in contrast, you can see that DefaultPort came from the TypeCatalog). Likewise, TestingSmtpHost has no [Part] listing and a [Part] listing for DefaultPort does exist.

Most of the time, you can analyze your composition using just the catalog, but the container can have parts too. When your container has parts, that’s when you’ll need to use VerifyCompositionInfo directly to get the full analysis.

You can download and play with the MailApp code from the Sample directory in the CompositionTests github repository.

Testing

What’s New in CompositionTests 1.2

After a great weekend at SoCalCodeCamp San Diego, I came home “super excited”.  After a good night’s sleep I got cracking first thing in the morning, the result is CompositionTests v1.2.0.

Thanks to github:pages the project has a pretty new home page at compositiontests.com.  You can head over there to check out the source.  If you just want the bits, they’re waiting for you on NuGet.org.

Read on to find out what’s new.

Built-in Scrubbers Handle Nulls Properly

Since scrubbers are called one after the other, its possible for one scrubber to nullify the entire string and pass it to the next.  The built in scrubbers all check for null and simply pass the value through without processing when one is encountered.  Custom scrubbers that don’t follow the same design risk a NullReferenceException at runtime.

Normalized Line Endings and Indentation

For some reason the (newer) exception messages generated by MEF use LF instead of CRLF when describing the contract name of the missing part.  This creates a usability issue when viewing the approved or received files in Visual Studio because Visual Studio displays a modal dialog that will offer to normalize the line endings for you.  But, if you normalize the line endings and approve, then you will never get a matching received file because the exceptions will not be normalized.  If you choose not to normalize the line endings in order to ensure consistency between the received and approved files, you will have to dismiss Visual Studio’s offer every time you open the file.

So, to make life easy, CompositionTests will normalize the line endings before sending the formatted text to ApprovalTests.

Likewise, the exception messages use tabs, while the CompositionInfoTextFormatter uses spaces.  Certain Visual Studio extensions will offer to normalize this for you.  On my system, this is not nearly annoying as Visual Studio, because the offer is not made in a modal dialog box and I can just ignore it if I like.  However, if someone were to normalize and approve the normalized file, they once again have broken consistency between the received and approved file.  So, CompositionTests will replace tabs with spaces before sending the formatted text to ApprovalTests.

New API (Backward Compatible for Now)

I had a chance to sit down with Llewellyn Falco at SoCalCodeCamp, and we did some pairing on ApprovalTests and CompositionTests.  We renamed the primary helper class from Composition to MefComposition since only MEF composition is supported.

We also created a specialized VerifyDirectoryCatalog method that automatically provides the scrubbers that make sense when working with a DirectoryCatalog.  From this starting point I created additional Verify* methods for each of the four supported catalog types.  The old DiscoverParts methods have been marked with the  ObsoleteAttribute, along with the old Composition class.

MefComposition still supports the old API, but the methods have been renamed.  You can find them by looking at the group of methods called VerifyCompositionInfo.  These methods can directly replace your calls to DiscoverParts and they still allow you to pass in a custom ExportProvider, etc.

These changes are meant to be backward compatible in this release, so if I’ve inadvertently broken compatibility, that’s a bug, let me know.  Please stop using DiscoverParts and Composition, they will be removed in a future release.

OrderedCompositionInfoTextFormatter.Format

I find it awkward to work with the Write method provided by CompositionInfoTextFormatter.  Since I’m now using OrderedCompositionInfoTextFormatter by default, I added a Format method that hides the parts I feel are awkward.

Semantic Versioning

I’m trying to adopt semantic versioning.  If I had adopted this system from the start, then I probably would not yet be at v1.  I’m already there, so I’m just going to try my best to follow this convention from now on.  Since I don’t want to go to v2 yet, I’ve tried to maintain backward compatibility with the old API, so this release puts us at v1.2.0.

To document the API, I’ve added an ApiApprover test.  Like CompositionTests, ApiApprover leverages ApprovalTests to introduce a cool new testing scenario.  The test discovers the public API, and will fail if the API changes.  Since it uses ApprovalTests, the public API ends up documented in the .approved file for the API Approver test.  So, you can find the public API listed out in “ApiTest.ApprovePublicApi.approved.txt” in the test folder.

Check It Out

Head over to the new homepage.  I’ve updated the Readme with some nice examples that should help get you up to speed and testing quickly.