Welcome to Manicprogrammer Sign in | Join | Help

Testing delegates with nUnit and nMock

Recently, I've been trying to put real unit tests around the Presenters in our MVP pattern, and because the view fires events to notify the Presenter of behavior from the user, I've had a need to inject the proper subscription and firing of those events into nMock (2). A huge goal of nMock is to avoid creating mock objects as explicit implementations of interfaces, so I didn't want to just give in and create full implementations for each view interface. The biggest miss, though, was confirming that the events had been properly subscribed to (as an expected condition) and then driving behavior into to component under test by firing that event with specific parameter values.

Being a good developer, I went searching (I won't say Googling, since some MS evangelists might be reading my blog, and recently gave me a dirty look for saying it during his presentation), and this was the closest I could find:
http://becomingagile.blogspot.com/2007/03/raising-events-in-nmock-20.html

It worked great... almost. It relied on the delegate being derived from System.EventHandler, and it only passed "null, null" for sender and args. Not good enough, but a HUGE step in the right direction. So, planning on expanding his code, I realized that the single "unknowable" was HOW exactly to call the delegate. Everything else could be handled by making the delegate type into a generic. Luckily, we have a new language mechanism for extracting those little bits of unknowable calls, so I figured an anonymous delegate could probably get me where I wanted to go. So here's what I did: (Full code at the bottom)

  1. Introduced a generic type parameter to both MockEvent<T> and MockEventHookup<T>, which represents the type of the delegate to be called.
  2. Introduced a generic delegate called void EventActivator<T>( T handler ), allowing the caller to specify the code to be executed to fire the event.
  3. Replaced all references to EventHandler with instances of T, and replaced the call to the event handler (In Raise) with a call to the EventActiviator I declared above

On the caller side, we end up with a new notation, but it pretty clearly expresses the intent... the ()'s next to handler would take any custom parameters for the delegate, and they would even be provided in the test's context.

             // Configure the view's mock
            MockEvent<EmptyEventHandlerDelegate> loadEvent
                = new MockEvent<EmptyEventHandlerDelegate>(
                    delegate(EmptyEventHandlerDelegate handler)
                    {
                        handler();
                    });

Then:

             Expect.Once
                 .On(view)
                 .EventAdd("OnLoadView", Is.Anything)
                 .Will(MockEvent < EmptyEventHandlerDelegate>.Hookup(loadEvent));
 And:

            loadEvent.Raise();


Here's the full code for the evolved mock event.

using System;
using System.Collections.Generic;
using System.Text;
using NMock2;
using NMock2.Monitoring;
using System.IO;

namespace Presentation.Tests.HelperObjects
{
    /// <summary>
    /// Code by Eric Willeke -- Keep my name here, please :)
    /// http://manicprogrammer.com/cs/blogs/willeke/archive/2007/10/17/testing-delegates-with-nunit-and-nmock.aspx
    /// Adapted from original code by Neil Bourgeois - Edmonton, Alberta, Canada
    /// http://becomingagile.blogspot.com/2007/03/raising-events-in-nmock-20.html
    /// </summary>
    public class MockEvent<T>
        where T : class
    {
        private T handler;
        EventActivator<T> activatingDelegate;

        public MockEvent(EventActivator<T> activatingDelegate)
        {
            if ( activatingDelegate == null )
                throw new ArgumentNullException();

            this.activatingDelegate = activatingDelegate;
        }

        public void Initialize(T handler)
        {
            if ( handler == null )
            {
                throw new ArgumentNullException();
            }

            this.handler = handler;
        }

        public void Raise()
        {
            activatingDelegate(handler);
        }

        public static IAction Hookup(MockEvent<T> mockEvent)
        {
            return new MockEventHookup<T>(mockEvent);
        }
    }

    public delegate void EventActivator<T>(T handler);

    public class MockEventHookup<T>
        : IAction
        where T : class
    {
        private readonly MockEvent<T> mockEvent;

        public MockEventHookup(MockEvent<T> mockEvent)
        {
            this.mockEvent = mockEvent;
        }

        public void Invoke(Invocation invocation)
        {
            T handler = invocation.Parameters[0] as T;

            if ( handler == null )
            {
                throw new Exception(
                    string.Format(
                        "Unknown event handler type. {0} was expected.",
                        typeof(T).ToString()));
            }

            mockEvent.Initialize(handler);
        }

        public void DescribeTo(TextWriter writer)
        {
            // do nothing
        }

    }
}

Published Wednesday, October 17, 2007 9:54 AM by willeke
Filed under:

Comments

# re: Testing delegates with nUnit and nMock

People have mentioned they've had issues using this approach, so I'm dumping a file that "should" work as is. I had to extract some NDA covered stuff, so it probably won't compile, but it should give a feel for the logic required.

internal static class MockHelpers

{

internal static T Mock<T>(Mockery mock)

{

return (T) mock.NewMock(typeof(T));

}

}

public class TestClass

{

public void ShouldConfigureViewCorrectly()

{

// "The" mock.

Mockery masterMock = new Mockery();

// Configure the view's mock

MockEvent<EmptyEventHandlerDelegate> loadEvent

= new MockEvent<EmptyEventHandlerDelegate>(

delegate(EmptyEventHandlerDelegate handler)

{

handler();

});

IView view = MockHelpers.Mock<IView>(masterMock);

using ( masterMock.Ordered )

{

Expect.Once

.On(view)

.EventAdd("OnLoadView", Is.Anything)

.Will(MockEvent < EmptyEventHandlerDelegate>.Hookup(loadEvent));

}

// Exercise the code under test

Presenter upp = new Presenter();

loadEvent.Raise();

masterMock.VerifyAllExpectationsHaveBeenMet();

}

}

Friday, November 30, 2007 1:24 PM by willeke

# Red Recondite &raquo; Blog Archive &raquo; Presenter First: Simple Presenters

# Nuvi 360 C550, 2009 Mercedes Benz S550 Wagon

Thursday, May 20, 2010 6:55 PM by Nuvi 360 C550, 2009 Mercedes Benz S550 Wagon

# Volkl Aura Skis Sale, Williamstown Restaurants

Thursday, May 20, 2010 7:40 PM by Volkl Aura Skis Sale, Williamstown Restaurants

# Vue Custom Laser Eye Surgery, Manual Hp Color Laserjet 2500

# 500e Auto Parts, 500e Clearance Centralized Management Csu Dsu

# Used Mercedes Sc400 Performance, Sc400 Deals

Friday, May 21, 2010 5:31 AM by Used Mercedes Sc400 Performance, Sc400 Deals

# Gmc P5100 Zone, 510 For Sale Mileage Purchasing Process

# Build Your Own Town Software, Used Lincoln Town Car Sale California

# 1995 Chrysler Lhs Sale Classified Listings, Lhs Aftermarket Auto Parts

# Electro Super Price, S550 Artwork

Saturday, May 22, 2010 6:04 AM by Electro Super Price, S550 Artwork

# Jeep Comanche Top Speed, 1986 Jeep Comanche Exhaust

Saturday, May 22, 2010 11:12 AM by Jeep Comanche Top Speed, 1986 Jeep Comanche Exhaust

# 1800 Cities, 1800 Performance Series

Saturday, May 22, 2010 11:38 AM by 1800 Cities, 1800 Performance Series

# 142 Performance Continued, 142 Women Snowboarding Gear

Saturday, May 22, 2010 11:47 AM by 142 Performance Continued, 142 Women Snowboarding Gear

# Spirit Sound Bugle Lyrics, Zvue Spirit May

Saturday, May 22, 2010 12:29 PM by Spirit Sound Bugle Lyrics, Zvue Spirit May

# Auto Prices Mercedes 300sdl Parts, 300sd Design 1983 Mercedes Benz

# Freightliner Top Truck Parts, Freightliner Parts Direct Dealers

# Xc70 Wagon Pictures, Xp Volvo Xc70 Headlight Bulb

Saturday, May 22, 2010 3:01 PM by Xc70 Wagon Pictures, Xp Volvo Xc70 Headlight Bulb

# 300td Windshield Washer Nozzle Spray, Sale 300td Mercedes Benz W123

# 1996 Chevy S10 Blazer Performance Parts, Luv Pickup Central Heating S10 Blazer

# 4x4 Chevy S 10 S10 Truck, Chevrolet S10 Engine Fender Flares

# 1977 Lincoln Versailles For Sale Leather Interior, Ch?teau De Versailles Castle

# Used Mx5 For Sale Kent, Second Hand Mazda Mx5 Cars

Saturday, May 22, 2010 7:10 PM by Used Mx5 For Sale Kent, Second Hand Mazda Mx5 Cars

# 1999 Monte Carlo Radiator Oxygen Sensor, 1998 Montero Reliability

# P10 Van Headlight P30 K5 Blazer, Toshiba P10 S429

Saturday, May 22, 2010 10:54 PM by P10 Van Headlight P30 K5 Blazer, Toshiba P10 S429

# Part Mercedes Benz 280sl 300sl Gullwing Sl63 Amg, 280sl Factory 450sl Slc - 243.tgrconversions.com

# B Granada B Nicaragua, Ford Granada Brake Swap - 95.tijuanareader.com

# 260z Promotion 280z 300zx, Nissan 300zx Tube Air Intake - 356.dlmreza.net

# B3500 Radiator 1999 Dodge Ram 2500, B3500 Clearance Apolipoprotein B 100 Familial Hypercholesterolemia - 156.cmanager.org

# Avenger Antique Appraisals, Avenger Radiator Promotion - 389.ja3ra.com

# Crown Victoria Body Lift, 1997 Ford Crown Victoria Owners Manual - 286.dlmreza.net

# 500sl Chassis Factory Service Manual Slk55 Amg, 2002 500sl - 302.myipgirl.com

# 2007 Volvo V50 Specs, V50 Replacement Quality - 165.jeepsunlimted.com

# Magnum Motorcycle Horn, A 2001 Ford F150 Projector Headlights Dodge Magnum - 281.computeronlinebingo.com

# Rebates New Buick Lucerne, Lacrosse Aftermarket Century Buick Lucerne - 336.jordanbrandallamerican.com

# Mazda Rx8 Headlight Assembly, Rx8 Legal - 439.defutbolazo.com

# Used Toyota Sequoia Engines, Toyota Sequoia Fender Suv - 76.binggreen.com

# 850i Fog Light Brake Pads, 850i Guide Thermaltake - 207.mfbattle.com

# Second Hand Kia Magentis Sale, Magentis Adoption Models - 317.luna-atra.net

# 2002 Saturn L300 Adapter, L300 2 Auto Stock - 277.zapstreaming.com

# Supplier Toyota Prius, Toyota Sienna 2008 Traction Control - 25.defutbolazo.com

# Insight Wall Opengl Es, Insight Bass Drum Pedal - 73.jordanbrandallamerican.com

# Bulb Gmc K2500 Discount, 08 Gmc Sierra Parts And Accessories - 72.tijuanareader.com

# C70 Part Art, Difference Between Volvo Xc70 Xc90 - 89.binggreen.com

# 1978 Fleetwood Brougham Cadillac Sedan Deville, 1940 Cadillac Fleetwood - 138.binggreen.com

# Honda Element Specifications, Cooling Systems Honda Element Radiator - 127.tijuanareader.com

# Honda Prelude H22a, Used 1998 Honda Prelude Sale - 387.defutbolazo.com

# R20 V20 Rural S10 Blazer, R20 Suburban Part Wiki - 167.binggreen.com

# Braintree High School Patriot Ledger, Patriot Lounge - 133.1fh.org

# Mr2 Spyder Parts 2002 Toyota Interior, Bulb 2007 Toyota Highlander Mr2 Spyder - 140.tgrconversions.com

# Sale 740i 750il Used Bmw Series, 750i Radiator 1994 Bmw - 109.defutbolazo.com

# Chevrolet Tahoe Performance Parts Camaro, Chevrolet Tahoe Silverado - 248.1fh.org

# 1998 Montero Sport Sale Specs, Monte Carlo Hall El Paso - 75.computeronlinebingo.com

# 280sl Ac Condensers, Mercedes Benz 280sl Aftermarket Cl55 Amg Body Parts - 449.binggreen.com

# 250se Discount Car Auto Parts, Replacement Compare Mercedes Benz 250se - 193.tvshowzone.com

# 1994 Suzuki Swift Body Kit, Ak Swift Lyrics - 145.akemet.com

# Chevrolet Chevette 80, Vauxhall Chevette Front Bumper Brake Caliper - 161.unlockiphone30.net

# J30 Cheap Best Buy, J30 Car Buy Used Owned - 415.renters.ws

# 2006 - 2005 @ K15 K1500 Pickup Discount Dimmer Switch Used Gmc Wiring Harness, K15 C1500 Auto Headlight Yukon Denali Xl - 445.1fh.org

# 1999 - 2008 @ 1965 Honda S90 Vintage, Volvo S90 Fog Light Bulb - 399.tvshowzone.com

# 1990 - 2007 @ Diamond Club Hollywood, E 450 Club Cab Wholesale - 133.rkwrh.com

# 2009 - 2006 @ E 450 Econoline Super Duty Aftermarket Bronco Ii Galaxie 500 Sedan Delivery, Super Duty Fender Badges - 46.tvshowzone.com

# 2000 - 1995 @ 1996 Eagle Talon Reviews, Eagle Sale Talon Cars Compare Used - 433.dlmreza.net

# 1996 - 1988 @ Integra Ad Our, Legend Radiator Integra 2006 Acura Rsx - 348.tvshowzone.com

# 1994 - 1987 @ Fairlane Torino 500 Mercury Comet Montego, Comet Electricals Also Sell - 460.dlmreza.net

# 1995 - 1997 @ Oem Oldsmobile Calais, Discount Oldsmobile Toronado Cutlass Calais Custom Cruiser - 77.rkwrh.com

# 1981 - 1984 @ 280sel Full Catalog Brake Pads, 280sel Part Numbers Auto Parts - 32.unlockiphone30.net

# 1984 - 2003 @ 1997 Mercury Cougar Specifications Automotive, Cougar Concept - 138.myipgirl.com

# 2008 - 1990 @ George Washington Martha Custis, Property Sale Bennington Vermont - 41.rkwrh.com

Anonymous comments are disabled