• Unit Test Fixtures

    Almost ten years ago, I bought and read Gerard Meszaros’ xUnit Test Patterns, Refactoring Test Code. It is very comprehensive and seeks to document all the common test design patterns. Meszaros uses italics to indicate named patterns, and I'll follow that convention here.

    The unit test framework I’ve used the most with .NET is NUnit. One quirk that I’m just beginning to understand better is the difference between Testcase Class and Fixture.

    My confusion lies with how NUnit requires that classes which contain test methods, be decorated with the TestFixture attribute. I always assumed that this meant the class was "the fixture", but no!

    Meszaros defines them as follows:

    (I) use ‘test fixture’ or just ‘fixture’ to mean ‘the pre-conditions of the test’ and Testcase class to mean ‘the class that contains the Test Methods and any code needed to set up the test fixture’. (xUnit Test Patterns p.59)

    The key thing is that while NUnit defaults to the Testcase Class per Fixture, you can do things differently.

    Take a look at one of the unit test projects from the Cake project.

    Cake.NuGet.Tests project structure

    Notice how they’ve separated the Fixture classes and the Testcase classes into separate folders.

    Here’s one of the test methods from the NuGetPackageInstallerTests class. Note how concise and uncomplicated it is. You can look at this method and very quickly understand what it’s testing.

    
    [Fact]
    public void Should_Be_Able_To_Install_If_Scheme_Is_Correct()
    {
        // Given
        var fixture = new NuGetPackageInstallerFixture();
        fixture.Package = new PackageReference("nuget:?package=Cake.Core");
    
        // When
        var result = fixture.CanInstall();
    
        // Then
        Assert.True(result);
    }
    

    Now let’s look at the fixture class – NuGetPackageInstallerFixture

    internal sealed class NuGetPackageInstallerFixture
    {
        public ICakeEnvironment Environment { get; set; }
        public FakeFileSystem FileSystem { get; set; }
        public IProcessRunner ProcessRunner { get; set; }
        public INuGetToolResolver ToolResolver { get; set; }
        public INuGetContentResolver ContentResolver { get; set; }
        public ICakeLog Log { get; set; }
    
        public PackageReference Package { get; set; }
        public PackageType PackageType { get; set; }
        public DirectoryPath InstallPath { get; set; }
    
        public ICakeConfiguration Config { get; set; }
    
        public NuGetPackageInstallerFixture()
        {
            Environment = FakeEnvironment.CreateUnixEnvironment();
            FileSystem = new FakeFileSystem(Environment);
            ContentResolver = Substitute.For<INuGetContentResolver>();
            Log = Substitute.For<ICakeLog>();
            Config = Substitute.For<ICakeConfiguration>();
    
            ToolResolver = Substitute.For<INuGetToolResolver>();
            ToolResolver.ResolvePath().Returns(new FilePath("/Working/tools/nuget.exe"));
    
            Package = new PackageReference("nuget:https://myget.org/temp/?package=Cake.Foo&prerelease&version=1.2.3");
            PackageType = PackageType.Addin;
            InstallPath = new DirectoryPath("./nuget");
    
            ProcessRunner = Substitute.For<IProcessRunner>();
            ProcessRunner.When(p => p.Start(Arg.Any<FilePath>(), Arg.Any<ProcessSettings>()))
                .Do(info => FileSystem.CreateDirectory(InstallPath.Combine(Package.Package.ToLowerInvariant()).Combine(Package.Package)));
        }
    
        public void InstallPackageAtSpecifiedPath(DirectoryPath path)
        {
            ProcessRunner.When(p => p.Start(Arg.Any<FilePath>(), Arg.Any<ProcessSettings>()))
                .Do(info => FileSystem.CreateDirectory(path));
        }
    
        public NuGetPackageInstaller CreateInstaller()
        {
            return new NuGetPackageInstaller(FileSystem, Environment, ProcessRunner, ToolResolver, ContentResolver, Log, Config);
        }
    
        public IReadOnlyCollection<IFile> Install()
        {
            var installer = CreateInstaller();
            return installer.Install(Package, PackageType, InstallPath);
        }
    
        public bool CanInstall()
        {
            var installer = CreateInstaller();
            return installer.CanInstall(Package, PackageType);
        }
    }
    

    As described in xUnit Test Patterns, this Test Fixture has everything we need in place to exercise the SUT (system under test). It instantiates both the SUT and all its dependencies, and also provides helper methods that are called by the Test Methods. Without this, all of the setup and configuration code would have lived in the Testcase class (NuGetPackageInstallerTests). This looks like an example of the Transient Fresh Fixture pattern.

    If you want to get another perspective on using test fixtures, I’d also recommend taking a look at Mark Seemann’s Advanced Unit Testing course on Pluralsight.

  • Enterprise Service Bus libraries for .NET – Rebus

    One in a series of posts giving a quick overview of ESB libraries for .NET

    Rebus describes itself as "a lean service bus implementation for .NET".

    https://github.com/rebus-org/Rebus

    Messages

    POCO classes

    Publishing

    Use an instance of IBus to publish.

    activator is an implementation of IHandlerActivator - either BuiltinHandlerActivator or an adapter class for your particular IoC container.

    activator.Bus.Publish(new DateTimeMessage(DateTime.Now)).Wait();
    

    Subscribing

    Handlers implement IHandleMessages<T>

    public class PrintDateTime : IHandleMessages<DateTime>
    {
        public async Task Handle(DateTime currentDateTime)
        {
            Console.WriteLine("The time is {0}", currentDateTime);
        }
    }
    

    And register a subscription

    activator.Bus.Subscribe<StringMessage>().Wait();
    

  • Enterprise Service Bus libraries for .NET – Shuttle ESB

    One in a series of posts giving a quick overview of ESB libraries for .NET

    Shuttle ESB describes itself as a "free .NET open-source enterprise service bus". It supports a good range of transports and integrates with a number of IoC containers.

    https://github.com/Shuttle/shuttle-esb

    Messages

    A POCO class

    Publishing

    Publish using IServiceBus. You'll also make use of static methods from the ServiceBus class.

    
    using (var bus = ServiceBus.Create(resolver).Start())
    {
        bus.Publish(new MemberRegisteredEvent
        {
            UserName = "Mr Resistor"
        });
    }
    

    Subscribing

    A handler implements IMessageHandler

    public class MemberRegisteredHandler : IMessageHandler<MemberRegisteredEvent>
    {
        public void ProcessMessage(IHandlerContext<MemberRegisteredEvent> context)
    
        {
            Console.WriteLine();
            Console.WriteLine("[EVENT RECEIVED] : user name = ‘{0}’", context.Message.UserName);
            Console.WriteLine();
        }
    }
    

    You also need to tell the subscription manager that you want to subscribe to a particular event. resolver is a wrapper class for your specific container.

    resolver.Resolve<ISubscriptionManager>().Subscribe<MemberRegisteredEvent>();