CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

June 2007 - Posts

  • Build your own CAB #11 - Event Aggregator

    I will finish "Build your own CAB" at least before Acropolis hits and makes it all obsolete.  In the meantime, check out all the stuff that's gone before:

    1. Preamble
    2. The Humble Dialog Box
    3. Supervising Controller
    4. Passive View
    5. Presentation Model
    6. View to Presenter Communication
    7. Answering some questions
    8. What's the Model?
    9. Assigning Responsibilities in a Model View Presenter Architecture
    10. Domain Centric Validation with the Notification Pattern
    11. Unit Testing the UI with NUnitForms
    12. Event Aggregator - This post
    13. Stopping Event Propagation with the "Latch" - Very closely related follow up to this post.  Forthcoming
    14. Embedded Controllers - Forthcoming
    15. MicroControllers - Forthcoming
    16. Other stuff...

    And no, there will definitely NOT be a "Build your own Acropolis" series here.

    Event Management is Hard

    A direct quote from my tester today:  "user interfaces are complicated critters."  From time to time I bump into the idea that Graphical User Interface (GUI) programming is easy stuff suitable for keeping the amateurs busy while the adults are busy on the server side.  My previous job involved very complex business logic behind a trivial GUI, but in systems like my current project the complexity of the GUI dwarfs the web services and database.  There are several things that potentially make GUI programming hard, but the worst culprit by far to me is the event driven nature of heavy, interactive clients.  A close second might be the synchronization of state between different parts of the user interface.  Here's an example to illustrate what I mean:

    Several years ago I found myself absurdly underused at work* with a brand new copy of the Gang of Four book on my bookshelf.  I naturally decided to teach myself design patterns by writing a fullblown grid and reporting system for DHTML written in JavaScript.  The easy stuff was easy, but things suddenly got harder when I started to put these pieces together:

    1. A grid control.  Given some data, an array of Column objects and ColorCoding objects, and a page size, make an HTML table on the fly.  Allow sorting from the grid
    2. A pager control
    3. A filter control that allowed you to filter data in the grid based on the unique values of the data set.  Think lot's of dropdowns
    4. A control that allowed you to customize the columns and color coding conditions
    5. A control that displayed the report header information

    Fine and great, except I  ran into two major problems.  The first problem was that I needed to synchronize all of the various components of the logical "Report" anytime things changed (new data, filter changed, sorting, turning columns on and off, changing to a different report, etc.).  What Martin Fowler calls flow synchronization turned out to be very clumsy.  Besides the "n squared" communication problem, not every page had the exact same set of components.  Having each component try to reach out and tell each other anytime the report state changed turned out to be a nightmare.  Plus, what if I wanted to add completely new types of components to new report screens?

    My second problem was the cascading event problem that's so painfully common in stateful GUI programming.  Resetting the data in the grid causes the filter control to refresh it's dropdown boxes, which could easily fire off the onchanged event of the dropdowns, which would fire off a command to reset the grid data, which could...    ...ripple all over the place. 

    I came to the conclusion that I needed to funnel all the events to a single class that would be responsible for propagating the events to all the other class's, and also to control the event propagation somewhat to shut down the rippling event problem.  New components could be added to the screen and take part in the reporting workflow just by being registered as listeners to my new "ReportManager" class.   What I came up with in the end was an implementation of the Event Aggregator design pattern.

    The Event Aggregator pattern is essentially a Publish/Subscribe infrastructure inside your WinForms application.  The Event Aggregator serves the same basic purpose as a messaging broker in a hub and spoke messaging architecture.   If you have any experience (that isn't repressed memory) with publish/subscribe messaging architectures like webMethods or Tibco this should be old news.  We can take much of the writings and patterns of loosely connected messaging and apply those lessons to the construction of composite user interfaces.  To handle all these events flying around we can compose our system into three groups:

    1. Subscribers that need to be told about events
    2. Publishers that raise the events in the first place
    3. A "Hub" that collects all of the events from the publishers and routes and/or transforms the events to the proper subscribers

    By channeling all of the events into a single hub we make it much easier to add new components to our user interface.  This is absolutely crucial for the kinds of composite applications we're trying to build now with WinForms solutions. 

    Example Event Aggregator in StoryTeller

    Here's the setup.  StoryTeller is, or will be shortly, a tool for editing and running acceptance tests with the FitnesseDotNet engine.  The WinForms client is meant to replace the FitNesse Wiki for running tests, and as you can easily imagine, there are a lot of screen updates when test changes or is executed.  Potentially, each test execution could effect:

    1. The TreeView control in the left pane that presents the Test/Test Suite hierarchy.  The TreeView nodes that represent tests change their icon to reflect the test's status as unknown, successful, failed, or exception.  Suspiciously similar to the NUnit GUI and every graphical test runner you've ever seen in your life.
    2. If it's open, the screen for editing a test.  Some options are only enabled when there is a previous result.  Visual cues need to change based on the result or state of the test.  When the test is changed I gray out the title bar.  When a test fails you get lots of red in the screen to indicate failure.
    3. Test grid pages.  I wanted the grid to update (turn the grid row red or green, update the counts, etc.) when the Tests change state. 

    All three of these UI elements need to be updated on the same events, but it would be foolish to tie all of these pieces together with the nonvisual code that actually executes the tests.  In Fowler speak, Flow Synchronization would lead to spaghetti code and undesirable coupling.  Instead, I used a centralized Event Aggregator class to perform Observer Synchronization.

    Most of the literature on using or building Event Aggregator's in WinForms applications revolves around using "Attribute magic" to define event subscribers and publishers.  I understand a little now about why people were so upset or dubious with my "roll your own CAB" statements.  The generic way CAB does Event Aggregator *is* complicated (but well within the reach of mere mortals if you were so inclined to do it).  When I say that you don't need the CAB it's not because I think I can quickly roll my own CAB, it's because I think I can write little specific point solutions and quite possibly be better off for it.

    My advice is to avoid the generic one size fits all Event Aggregator implementation for something specific to your own application with interfaces that are expressed in the terms of your problem domain.  Make your Event Aggregator publish and subscribe events that are specific and meaningful to your problem domain.  By making the events specific, the semantics of the code should be far more intention revealing than code like EventBroker.RaiseEvent("event://some string/more string/event name", new GenericEventArgs()) can ever be.  I'm plenty happy to write a little bit of custom, specific code if the payoff is better understandability. 

    For StoryTeller, I took a very simple, direct path to creating an event aggregator for testing events.  Let's ignore the publisher and hub pieces of event aggregation for now.  The subscribers in StoryTeller need to expose and implement an Observer interface called ITestObserver with four methods:

        public interface ITestObserver

        {

            void StateIsUnknown(Guid testId);

            void StartedRunning(Guid testId);

            void Completed(TestResult result);

            void Queued(Guid testId);

        }

    What I was aiming for with this design was semantic clarity and a strong contract.  From an implementation standpoint it becomes pretty easy to organize the code that responds to test events.  The first class to get the ITestObserver treatment was the TreeNode subclass for StoryTeller Test's:

    public class TestNode : LeafNode<Test>, ITestObserver

    TestNode is a descendent of TreeNode that represents a Test within the TreeView explorer view.  TestNode changes it's display when any of the ITestObserver methods are called.  For example, when a test run starts the StartedRunning() method is called.  The TestNode will change its icon to a question mark to denote that the outcome is unknown, and change the TreeNode.Text to "name of the test (Executing)" to give some visual indication of which test is currently being executed.  Here are a couple of the observer methods are just this:

     

            public void StateIsUnknown(Guid testId)

            {

                _lastResult = null;

     

                _context.Send(

                    delegate

                        {

                            Text = Subject.Name;

                            RefreshImages();

                        }, null

                    );

            }

     

            public void StartedRunning(Guid testId)

            {

                _lastResult = null;

     

                _context.Send(

                    delegate

                        {

                            changeIcon(StoryTellerConstants.IGNORED);

                            Text = Subject.Name + " (Running)";

                        }, null

                    );

            }

    The TestNode just changes its text and icon to reflect the status of the Test.  Since we've made it clear (I hope) that we don't want the test execution engine to "know" about the TreeView in the main screen, and the TestNode's certainly don't execute the Test's themselves, something else has to tell the ITestObserver's about Test events.  The "hub" for publishing and subscribing to Test events in StoryTeller is an interface called ITestEventPublisher shown below:

     

        [PluginFamily("Default", Scope = InstanceScope.Singleton)]

        public interface ITestEventPublisher

        {

            void RegisterForTestEvents(ITestObserver observer, Test test);

            void UnRegister(ITestObserver observer, Test test);

            void PublishResult(Test test, TestResult result);

            void MarkAsQueued(Test test);

            void MarkAsUnknown(Test test);

            void MarkAsExecuting(Test Test);

     

            TestResult GetLastResult(Guid testId);

        }

    The [PluginFamily] attribute decorating the interface is just declarative wiring configuration for StructureMap (you don't have to use attributes for configuration).  Part of the StructureMap configuration is to only create a single instance of ITestEventPublisher for the entire AppDomain.  Anytime another class retrieves ITestEventPublisher through service location or ITestEventPublisher is injected into a constructor function the same single instance will be returned.  In effect, we're just letting StructureMap handle the Singleton mechanics for us.  It is, however, of the utmost importance to depend on the abstracted ITestEventPublisher interface rather than the concrete implementation (Chill out on the Singleton Fetish).

    If you'll note the UnRegister(ITestObserver, Test) method for a second.  In this particular case I have reasons to explicitly unregister listeners.  In normal usage I'm having each screen unregister itself when it's closed to make sure that the garbage collection can reclaim the screen.  Most people are taking advantage of WeakReference's to solve the garbage collection problem (if the publisher keeps a reference to each observer, the observers can not be garbage collected).

    You'll also note that the RegisterForTestEvents(ITestObserver, Test) method explicitly requires you to specify the Test (the event subject) that the listener is interested in.  In this case I'm making the concrete implementation of ITestEventPublisher responsible for remembering who's listening to which tests.  Otherwise, you could have the publisher broadcast messages to each subscriber and just assume that the subscribers will be responsible for ignoring irrelevant events.  I've never liked that approach in real messaging infrastructure, but I don't see it being that big of a difference inside a single process.  In the StoryTeller case I thought that it made the implementation simpler to make the subscribers dumb.

    Back to registering subscribers.  Any class that listens for test execution events needs to register itself for each test with the an instance of ITestEventPublisher.  The TestNode class registers itself in it's constructor function by retrieving the configured instance of ITestEventPublisher from StructureMap and passing itself into the RegisterForTestEvents(ITestObserver, Test) method:

     

            public TestNode(Test subject) : base(subject.Name, subject)

            {

                // Other setup that isn't relevant to the Event Aggregation

                ...

     

                // Grab the Event Aggregator out of StructureMap and register

                // for any events related to the Subject of the node

                ITestEventPublisher publisher = ObjectFactory.GetInstance<ITestEventPublisher>();

                publisher.RegisterForTestEvents(this, subject);

     

                // Simple initialization

                StateIsUnknown(subject.TestId);

            }

    If you've been following Scott Bellware's posts on dependencies, you'll recognize ITestEventPublisher as a transitive dependency of the TestNode.  Once TestNode registers itself with ITestEventPublisher there's no more need to keep a reference around.

    The internals of the concrete TestEventPublisher aren't particularly that complicated.  The registered subscribers are stored in a Dictionary like this**:

            private Dictionary<Guid, List<ITestObserver>> _observers

                = new Dictionary<Guid, List<ITestObserver>>();

     

    The methods for raising events to the subscribers look like these two below.  Just find the ITestObserver's that are interested in a particular Test and fire the appropriate method for each subscriber.

     

            public void MarkAsQueued(Test test)

            {

                test.Status = TestStatus.Queued;

                foreach (ITestObserver observer in GetObservers(test))

                {

                    observer.Queued(test.TestId);

                }

            }

     

            public void MarkAsUnknown(Test test)

            {

                test.Status = TestStatus.Unknown;

                foreach (ITestObserver observer in GetObservers(test))

                {

                    observer.StateIsUnknown(test.TestId);

                }

            }

     

    Inside of the unit tests for TestEventPublisher I use RhinoMocks to test the interaction of the TestEventPublisher with the ITestObserver's.  The first set of unit tests just checks that TestEventPublisher is correctly associating ITestObserver's with the proper Test subjects (I'll spare you the details).  After that I wrote tests like the following that verifies that the ITestObserver.Completed(TestResult) method is fired on the correct ITestObserver's whenever ITestEventPublisher.PublishResult(Test, TestResult) is called.

            private TestEventPublisher setupMockedPublisher()

            {

                // Using a Self-Mock for TestEventPublisher

                // I've already unit tested the GetObservers(Test) method,

                // so I'd like to remove that little wrinkle from the other tests

                TestEventPublisher publisher = _mocks.CreateMock<TestEventPublisher>();

     

                Expect.Call(publisher.GetObservers(test1))

                    .Return(_observerArray)

                    .Constraints(new Equal(test1));

     

                return publisher;

            }

     

            [Test]

            public void PublishResult()

            {

                TestEventPublisher publisher = setupMockedPublisher();

     

                TestResult result = new TestResult();

                foreach (ITestObserver observer in _observerArray)

                {

                    observer.Completed(result);

                }

     

                _mocks.ReplayAll();

     

                publisher.PublishResult(test1, result);

     

                _mocks.VerifyAll();

            }

     

    Great, we've got an interface for subscribers and a unit tested hub (TestEventPublisher).  Now all we need is to actually fire off the events from the publishers.  Instead of opting for more indirection like the CAB, I just have the publishers call methods directly on the ITestEventPublisher interface.  Again, I think it's simpler and makes the code more intention revealing (the CTRL-B factor as well).  If you want more decoupling you could have the hub listen to events on the publishers and then relay and/or transform the events to the subscribers. 

    One way or another, the publishers get the single instance of ITestEventPublisher from StructureMap.  The presenter for the screen that let's you edit a Test gets a reference from constructor injection.

     

            public TestEditorPresenter(ITestView view, ITestFormatConverter converter, ITestEventPublisher publisher,

                                       ICommandExecutor executor)

                : base(view, converter)

            {

                _publisher = publisher;

                _executor = executor;

            }

    The publisher I want to look at is called ExecutionEngine.  Internally, it's responsible for managing and coordinating the workflow of running tests.  In this case ITestEventPublisher is a transparent dependency that ExecutionEngine interacts with throughout it's lifetime.

     

            public ExecutionEngine(ITestRunner runner, IComponentAnalyzer[] analyzers, ITestEventPublisher publisher)

            {

                _runner = runner;

                _analyzers = analyzers;

                _publisher = publisher;

            }

     

    Deep inside of ExecutionEngine it has a private method that actually executes a batch of tests. 

     

            private List<TestResult> executeTests(Test[] tests)

            {

                List<TestResult> list = new List<TestResult>();

     

                foreach (Test test in tests)

                {

                    Console.WriteLine("Running Test " + test.GetFullPath());

     

                    _publisher.MarkAsExecuting(test);

     

                    TestResult result = _runner.ExecuteTest(test);

                    list.Add(result);

     

                    _publisher.PublishResult(test, result);

     

                    Console.WriteLine("  " + result.Counts.ToString());

                }

     

                return list;

            }

    ExecutionEngine calls the ITestEventPublisher.MarkAsExecuting(Test) method just before executing a Test and publishes the result afterwards with the ITestEventPublisher.PublishResult(Test, TestResult) method to let the subscribers know that an individual test is finished.  This is important functionality.  The StoryTeller tests can often be slow to execute because they're usually integration tests, and it's very handy to both give some UI cues about the progress and also allow the user to begin reviewing the test results while the remaining tests execute.  It's a huge advantage over the FitNesse Wiki tool that I'm trying to replace with StoryTeller. 

    Part of the unit test for running a batch of tests is shown below.  I'm using RhinoMocks "ordered" mode to validate that the interactions happen in the correct order.

     

                using (mocks.Ordered())

                {

                    // Other stuff

     

                    publisher.MarkAsExecuting(test1);

                    Expect.Call(runner.ExecuteTest(test1)).Return(result1).Constraints(new Equal(test1));

                    publisher.PublishResult(test1, result1);

     

                    publisher.MarkAsExecuting(test2);

                    Expect.Call(runner.ExecuteTest(test2)).Return(result2).Constraints(new Equal(test2));

                    publisher.PublishResult(test2, result2);

     

                    publisher.MarkAsExecuting(test3);

                    Expect.Call(runner.ExecuteTest(test3)).Return(result3).Constraints(new Equal(test3));

                    publisher.PublishResult(test3, result3);

     

                    publisher.MarkAsExecuting(test4);

                    Expect.Call(runner.ExecuteTest(test4)).Return(result4).Constraints(new Equal(test4));

                    publisher.PublishResult(test4, result4);

     

                    // Other Stuff

                }

     

    So far I'd say that the TestEventPublisher design has worked out rather well.  The one issue I didn't mention was thread synchronization as the TestEventPublisher could easily be running in a background thread instead of the UI thread.  I'll leave that solution up to you dear reader;)  On a serious note, do be aware of the thread synchronization issue here.

    The rest of the code for the Event Aggregation in StoryTeller can be found in the Subversion trunk here:  http://storyteller.tigris.org/svn/storyteller/trunk/src.

    More Resources

    Besides the ever useful www.martinfowler.com site, check out these resources for different approaches to Event Aggregation:

     

    Next

    The next post is a closely related followup to this post on the "Latch" strategy for controlling event rippling.

     

     

    * Immediately following a successful project that had me working about 4 out of 5 weekends for almost six months.  I'd say that it was a justified at work vacation except that it was mostly due to managerial malfeasance.  My "official" and measurable output for about three months was a couple sentences in a current state analysis document.  Almost verbatim:  "Every process runs under the admin account.  There is no security."

    ** C# 3.0 type inference anyone?  Seriously.  I love the newer, more powerful language features of C# 2.0, but in some ways it's been a huge step backwards in terms of code aesthetics.  I'm feeling like C# 2.0 was really just the beta for 3.0.

  • Designing for Testability

    EDIT:  What I should really say is that it isnt' just Designing for Testability, it's Designing with Testability 

    From a question on my Passive View blog post

     "should we design for testability, or should we try and test what's designed (perhaps designed badly, so we refactor later)?"

    Here's my take:

    "Done, done, done" isn't just writing code.  It's writing code and verifying that that code works correctly.  You don't ship until the code is proven to work (hopefully).  Designing for testability might cost you extra time in coding (which I would actually dispute somewhat), but can easily save time in the whole by cutting down on the time spent debugging and testing.  I see testability design as a way to optimize the time to deliver, even if it ups the time spent on design or coding.

    One of the very painful truths that TDD newbies learn the hard way (myself included) is that retrofitting automated tests to existing code can be very difficult.  Just trying to test what's designed may not work out very well, and frankly, I have yet to see a codebase that wasn't built with TDD that was easy to test.

    What is Testability design anyway?  Granted, there are some things I do like opening up more public accessors or pulling out more interfaces strictly for testing that could arguably described as "bad."  However, most of what constitutes designing for testability, or using testability as a design heuristic, is a matter of how best to assign responsibilities by following older design principles that predate TDD by many years.  Achieving testability is mostly a matter of separation of concerns, coupling between classes and subsystems, and cohesion.  Exactly the design qualities that we've always strived for to make our code maintainable.  It's what we've been trying to do anyway.  If you practice traditionally good design, you might already be there to testability. 

    Testability is, in my opinion, the ultimate design smell detector at the granular level.  If you're finding it hard to unit test your code, you've likely got a coupling or cohesion problem.  Testability is yet one more design tool to stick in your design toolbox right between UML/CRC modeling and code smells.  At least think of it this way, driving an application design at least partially through tests is yet another example of starting with the end in mind.  How will I know that this code works correctly?  How will I know that I'm done?

    Yes, using TypeMock or switching to a dynamic typed language will let you more readily create testing seams with less conscious effort, but that's not the entire ballgame.  Throw testability and orthogonality out the window to write a ball of mud and no amount of TypeMock magic is going to help you out.

     

    Anyway, go ahead and start arguing with me.  As always, comments are open.

  • Build your own CAB Part #10 - Unit Testing the UI with NUnitForms

    I've long, long since left the rails of "Build your own CAB" topics and wandered off into "just things you do" when you're building a WinForms application.  I'm doing this topic now because it felt easy to do in the midst of a hectic week before some time off.  Other topics will follow shortly dependent upon my bouts with writer's block.

    Previously on Soap,

    1. Preamble
    2. The Humble Dialog Box
    3. Supervising Controller
    4. Passive View
    5. Presentation Model
    6. View to Presenter Communication
    7. Answering some questions
    8. What's the Model?
    9. Assigning Responsibilities in a Model View Presenter Architecture
    10. Domain Centric Validation with the Notification Pattern

    Confused?  Well, you won't be after this week's episode of Soap.

    I've frequently read critiques of Test Driven Development that question it's effectiveness or practicality in regards to user interface code.  It's certainly more challenging to test drive user interface code, but it's still very practical.  There is some specific "lore" that TDD practitioners have created over the last couple years to address automated unit testing against user interface code.  The best single answer in my book is to utilize Humble View's of some sort or another to remove as much code as possible from the clutches of the WinForms presentation infrastructure.  At some point though, you're left with the actual View code and it's a nice cozy home for bugs to breed in.  You can take a rationalized approach and say that you've reduced the View to code that's so simple that it's not worth the time investment to unit test the View's with automated tests.  Another option that we'll explore here is to unit test the WinForms View classes with the  NUnitForms library.

    NUnitForms

    I've been meaning to write a post on using NUnitForms for a long time because it's a great tool that's never gotten the attention that I think it deserves.  NUnitForms is a library that can be used from within any of the xUnit tools (NUnit/MbUnit/MSTest) to enable unit testing of View behavior.  NUnitForms can drive a screen by finding and manipulating the controls on a screen, as well as check properties of controls at runtime.  For the most part I only use NUnitForms to write very simple unit tests on the wiring from View to Presenter, but NUnitForms can go much farther than that.  In an earlier post I decried the usage of the Autonomous View as a generally untestable and unmaintainable mess.  While I think that's definitely the case for a screen of any nontrivial complexity, we can happily unit happily forgo View/Presenter separation for smaller screens without sacrificing unit test coverage.  Let's take one last look at the sample Shipping screen from the Supervising Controller post and see how we could test that screen with NUnitForms if we had taken an autonomous view approach.

    Here's part of the code for that screen:

     

        public partial class ShippingScreen : Form

        {

            private IShippingService _service;

            private Shipment _shipment;

     

     

            public ShippingScreen()

            {

                InitializeComponent();

     

                // Grab an instance of IShippingService from StructureMap

                _service = ObjectFactory.GetInstance<IShippingService>();

     

                // set the Shipment property and start up the data binding

                Shipment = new Shipment();

     

     

                shippingVendorField.SelectedIndexChanged += new System.EventHandler(shippingVendorField_SelectedIndexChanged);

                shippingOptionField.SelectedIndexChanged += new System.EventHandler(shippingOptionField_SelectedIndexChanged);

            }

     

            // Reset the checkbox enabled states anytime a different Shipping Option is selected

            void shippingOptionField_SelectedIndexChanged(object sender, System.EventArgs e)

            {

                resetDeliveryOptions();

            }

     

            // When a new vendor is selected, fill the Shipping Option ComboBox

            // and reset the Delivery Option checkbox's

            void shippingVendorField_SelectedIndexChanged(object sender, System.EventArgs e)

            {

                // When the Vendor is selected, cascade the list for Shipping Options

                string[] options = _service.GetShippingOptions(_shipment);

                shippingOptionField.Items.Clear();

                shippingOptionField.Items.AddRange(options);

                shippingOptionField.SelectedIndex = 0;

     

                resetDeliveryOptions();

            }

     

            private void resetDeliveryOptions()

            {

                DeliveryOptions options = _service.GetDeliveryOptions(_shipment);

                purchaseInsuranceField.Enabled = options.PurchaseInsuranceEnabled;

                requireSignatureField.Enabled = options.RequireSignatureEnabled;

            }

     

     

            public Shipment Shipment

            {

                set

                {

                    // start up the data binding stuff

                    _shipment = value;

                }

            }

        }

    Easy enough.  Let's start the unit test harness.  We'll create our normal NUnit TestFixture class, but this time we'll inherit from NUnitForm's NUnitFormTest class to utilize some of it's bookkeeping code.

     

        // You don't have to inherit from NUnitFormTest, but it adds some

        // bookkeeping functionality that you may want

        [TestFixture]

        public class ShippingScreenTester : NUnitFormTest

        {

            private ShippingScreen _screen;

     

            private ComboBoxTester stateComboBox;

            private ComboBoxTester shippingVendorComboBox;

            private CheckBoxTester purchaseInsuranceCheckBox;

            private CheckBoxTester requireSignatureCheckBox;

            private TextBoxTester costTextBox;

            private ComboBoxTester shippingOptionComboBox;

     

            private MockRepository _mocks;

            private IShippingService _service;

     

            // Override Setup()

            public override void Setup()

            {

                // I'm using a mock object for the ShippingService here

                // I could just as easily have used a stub, but I can't stand

                // having those cluttering up the code.

                // It's somewhat personal preference

                _mocks = new MockRepository();

                _service = _mocks.CreateMock<IShippingService>();

                ObjectFactory.InjectStub(_service);

     

                _screen = new ShippingScreen();

                _screen.Show();

     

                // Create a ControlTester for each field on the screen for later

                stateComboBox = new ComboBoxTester("stateField");

                shippingVendorComboBox = new ComboBoxTester("shippingVendorField");

                purchaseInsuranceCheckBox = new CheckBoxTester("purchaseInsuranceField");

                requireSignatureCheckBox = new CheckBoxTester("requireSignatureField");

                costTextBox = new TextBoxTester("costField");

                shippingVendorComboBox = new ComboBoxTester("shippingOptionField");

            }

     

            // VERY IMPORTANT!  CLOSE THE SCREEN WHEN YOU'RE DONE!

            public override void TearDown()

            {

                _screen.Dispose();

            }

        }

    Take a long look at the Setup() method because there's a lot going on.  The first 3 lines are just setting up the RhinoMocks for IShippingService and directing StructureMap to return the mock object whenever an instance of IShippingService is requested (that's what the ObjectFactory.InjectStub<T>(T value) method is doing).  The next two lines just create a new instance of the ShippingScreen form and make it visible.  That's all you need to do.  NUnitForms will happily latch onto the visible form later.

    The next thing is to set up "ControlTester" objects for each of the UI controls on the screen.  Each ControlTester is responsible for finding the named control and provides convenience methods to both manipulate a control and check it's properties.  There are prebuilt ControlTester classes for all of the most common controls plus a generic ControlTester that can be used for everything else.  You can also use a GenericTester like this one:

     

            [Test]

            public void EnableAndDisableCheckboxsWhenTheShippingOptionIsChanged()

            {

                // First, document some preconditions to prove that the code actually did something

                Assert.IsFalse(requireSignatureCheckBox.Properties.Enabled);

                Assert.IsFalse(purchaseInsuranceCheckBox.Properties.Enabled);

     

                string theShippingOptionSelected = "Next Day"// I think I picked up the habit of naming test data

                                                // variables "theSomething" from Colin Kershaw, but

                                                // I don't completely remember.

     

                DeliveryOptions theDeliveryOptionsReturnedFromTheService = new DeliveryOptions();

                theDeliveryOptionsReturnedFromTheService.PurchaseInsuranceEnabled = true;

                theDeliveryOptionsReturnedFromTheService.RequireSignatureEnabled = true;

     

                // Look at the Constraint.  Little RhinoMocks trick to verify that the "ShippingOption"

                // property on the internal Shipment object has been set prior to making the call to

                // IShippingService.GetDeliveryOptions(Shipment)

                Expect.Call(_service.GetDeliveryOptions(null))

                    .Return(theDeliveryOptionsReturnedFromTheService)

                    .Constraints(new PropertyIs("ShippingOption", theShippingOptionSelected));

     

                _mocks.ReplayAll();

     

                // Select a Shipping Option

                shippingOptionComboBox.Enter(theShippingOptionSelected);

     

                _mocks.VerifyAll();

     

                // Check the enabled property on the two checkbox's

                Assert.AreEqual(

                    theDeliveryOptionsReturnedFromTheService.PurchaseInsuranceEnabled,

                    purchaseInsuranceCheckBox.Properties.Enabled);

     

                Assert.AreEqual(

                        theDeliveryOptionsReturnedFromTheService.RequireSignatureEnabled,

                        requireSignatureCheckBox.Properties.Enabled);

            }

    Back to our shipping screen.  Here's the unit test for the cascading dropdown logic when a state or province is selected.  The unit test below does the following:

    1. Set up an expectation on the mock object for IShippingService to return an array of shipping vendor names
    2. Select an option on the dropdown box for "State or Province" (the call to stateComboBox.Enter())
    3. Verify the mock object interaction with the IShippingService
    4. Lastly, check the values on the dropdown box for the shipping vendor

            [Test]

            public void SelectingAStateOrProvinceCascadesTheSelectionListOfVendors()

            {

                // Setup the IShippingService to return a string array of vendors for a given State

                string[] theOptions = new string[]{"Vendor A", "Vendor B", "Vendor C"};

                string theStateOrProvince = "TX";

     

                Expect.Call(_service.GetShippingVendorsForLocation(theStateOrProvince))

                    .Return(theOptions)

                    .Constraints(new Equal(theStateOrProvince));

     

                _mocks.ReplayAll();

     

                stateComboBox.Enter(theStateOrProvince);

     

                _mocks.VerifyAll();

     

                // Lastly, let's check the dropdown list on shippingVendor ComboBox

                // The "Properties" property is a reference to the System.Windows.Forms.ComboBox

                // object.  You can write assertions against anything on its public API

                Assert.AreEqual(theOptions, shippingVendorComboBox.Properties.Items);

            }

    Now, let's look at a unit test for enabling/disabling the insurance and signature required checkbox's when the Shipping Option is selected:

     

            [Test]

            public void EnableAndDisableCheckboxsWhenTheShippingOptionIsChanged()

            {

                // First, document some preconditions to prove that the code actually did something

                Assert.IsFalse(requireSignatureCheckBox.Properties.Enabled);

                Assert.IsFalse(purchaseInsuranceCheckBox.Properties.Enabled);

     

                string theShippingOptionSelected = "Next Day"// I think I picked up the habit of naming test data

                                                // variables "theSomething" from Colin Kershaw, but

                                                // I don't completely remember.

     

                DeliveryOptions theDeliveryOptionsReturnedFromTheService = new DeliveryOptions();

                theDeliveryOptionsReturnedFromTheService.PurchaseInsuranceEnabled = true;

                theDeliveryOptionsReturnedFromTheService.RequireSignatureEnabled = true;

     

                // Look at the Constraint.  Little RhinoMocks trick to verify that the "ShippingOption"

                // property on the internal Shipment object has been set prior to making the call to

                // IShippingService.GetDeliveryOptions(Shipment)

                Expect.Call(_service.GetDeliveryOptions(null))

                    .Return(theDeliveryOptionsReturnedFromTheService)

                    .Constraints(new PropertyIs("ShippingOption", theShippingOptionSelected));

     

                _mocks.ReplayAll();

     

                // Select a Shipping Option

                shippingOptionComboBox.Enter(theShippingOptionSelected);

     

                _mocks.VerifyAll();

     

                // Check the enabled property on the two checkbox's

                Assert.AreEqual(

                    theDeliveryOptionsReturnedFromTheService.PurchaseInsuranceEnabled,

                    purchaseInsuranceCheckBox.Properties.Enabled);

     

                Assert.AreEqual(

                        theDeliveryOptionsReturnedFromTheService.RequireSignatureEnabled,

                        requireSignatureCheckBox.Properties.Enabled);

            }

     

    Testing View to Controller Communication

     

    Most of our NUnitForms unit tests are just verifying the wiring of a View to a Presenter.  As expected, I've gotten a mostly negative reaction to my preference for making the View communicate directly with the Presenter.  One of the commenters questioned whether or not my direct communication would lead to harder testing.  Here's a sample of testing both direct communication and communication through events.  I don't think you're going to see much difference in effort either way.

    Here's the scenario:  when the "Save" button is clicked, call the Save() method on the Presenter.

     

        public interface IPresenter

        {

            void Save();

        }

     

        public class SomeScreen : Form

        {

            private IPresenter _presenter;

            private Button saveButton;

     

            public void AttachPresenter(IPresenter presenter)

            {

                _presenter = presenter;

            }

        }

     

        [TestFixture]

        public class DirectCommunicationTester

        {

            private SomeScreen _screen;

            private MockRepository _mocks;

            private IPresenter _presenter;

     

            [SetUp]

            public void SetUp()

            {

                _screen = new SomeScreen();

     

                // Setup RhinoMocks for the IPresenter and attach it

                _mocks = new MockRepository();

                _presenter = _mocks.CreateMock<IPresenter>();

                _screen.AttachPresenter(_presenter);

     

                _screen.Show();

            }

     

            [TearDown]

            public void TearDown()

            {

                _screen.Dispose();

            }

     

            public delegate void VoidHandler();

     

            // A helper function.  This pays off over the application

            private void assertClickingButtonCalls(string buttonName, VoidHandler handler)

            {

                // Set up the expectation on the Presenter

                handler();

                _mocks.ReplayAll();

     

                // Find the button on the screen

                ButtonTester button = new ButtonTester(buttonName);

     

                // Click the button

                button.Click();

     

                // verify the interaction with the Presenter

                _mocks.VerifyAll();

            }

     

            [Test]

            public void ClickTheSaveButtonCallsSaveOnThePresenter()

            {

                assertClickingButtonCalls("saveButton", delegate {_presenter.Save();});

            }

        }

    It's important to note that you generally make all calls to the presenter take in zero arguments.  We'll see that same pattern repeat for event communication.  You can go farther with the test helper methods to make testing even more declarative. 

    Now, the same thing with event driven communication using an anonymous delegate as the event handler:

     

        public delegate void VoidHandler();

     

        public class EventScreen : Form

        {

            private IPresenter _presenter;

            private Button saveButton;

     

            public event VoidHandler OnSave;

        }

     

        [TestFixture]

        public class EventCommunicationTester

        {

            private EventScreen _screen;

     

            [SetUp]

            public void SetUp()

            {

                _screen = new EventScreen();

                _screen.Show();

            }

     

            [TearDown]

            public void TearDown()

            {

                _screen.Dispose();

            }

     

            [Test]

            public void ClickTheSaveButton()

            {

                bool IWasCalled = false;

                _screen.OnSave += delegate { IWasCalled = true; };

                Assert.IsTrue(IWasCalled);

            }

    So it's okay to use Autonomous View after all?

    Because of NUnitForms I'm perfectly happy to use the autonomous view style on simple dialog screens, but that's just about it.  There's a certain fuzzy point where I'd definitely choose to go to a separated presentation as opposed to an autonomous view.  Even though the shipping screen above is small, I think it already crosses that line.  Many people will term any kind of Model View Presenter (MVP) architecture as more complicated than the autonomous view because of the additional pieces, but I see it differently.  I reject the notion that more classes automatically equals more complexity.  I'd much rather have more classes if that enables me to keep any one single class as simple as possible.  Testability is a huge part of maintainability in my book, but separation of concerns by itself will make the code better organized and easier to understand.

    At least in the .Net world the MVP style of construction isn't being received well by mainstream developers because it's a foreign approach that isn't encouraged by the .Net tooling.  In a way MVP is more complex in .Net just because the tooling doesn't lead you there.  I wouldn't say that you have to fight the .Net tooling to do separated presentation, but you've got to make all of the decisions yourself.I guess it's easy to understand the negative reaction I see to MVP because it's not part of the .Net canon yet.  I haven't taken a hard look at Acropolis yet, but it apparently encourages some sort of View/Presenter separation.  That's a positive change in direction in .Net tooling that'll do more good than a thousand blog posts on MVP.

     

    Lessons Learned

    NUnitForms is definitely meant for unit testing, and that's where I've found it to be most applicable.  On my last project we tried to drive the WinForms application in FitNesse acceptance tests with NUnitForms and struggled mightily.  The complexity of the testing effort goes up dramatically when you move from testing one form or control to the full application at one time.  I'm using StoryTeller/FitnesseDotNet for story testing of the user interface quite successfully on my current project, but that's a later post.

     

    The Future

    NUnitForms was written by Luke Maxon with some contributions from Levi Haskell (probably the best developer I've ever worked with).  Since Luke's off living the exciting start up life and coding in Java, I've volunteered(?) to be one of the SourceForge administrators for the NUnitForms project now.  I'm thinking of making some additions to NUnitForms for better support of acceptance testing and possibly some prebuilt Fit fixtures, but I'm not sure of either direction or timing.  Since my company does so much WinForms work, I'm going to try to rook some of my colleagues into helping too.  I'm also kicking around the idea of creating a sort of testing DSL with NUnitForms to support something reminiscent of Brian Marick's wireframe test idea, and possibly use that for acceptance testing as opposed to Fit tests.  I definitely want to add some custom assertions and more options for locating controls.  Got any ideas or requests?  Here's some loose conceptual code, feel free to let rip with what you think:

     

    using (NUnitFormsSpecification specification = new NUnitFormsSpecification){
    Click.Button.WithText("Do Something");
    Click.Button.Named("saveButton");
    CheckBox.WithText("Some flag").Should.Be.Enabled;
    Control.Named("bodyPanel").Should.Be.Hidden;
    ComboBox.Named("names").Should.Have.Items(new string[]{"Jeremy", "Scott", "Karl", "Jeffrey"});
    Select("Jeremy").For.ComboBox.Named("names");

    }
     
  • If you want your process to be followed consistently...

    ...make your process easy to follow.  Seriously.  If I have to go out of my way to do some sort of bookkeeping that bookkeeping isn't going to happen with the consistency that the metrics loving guy is going to want.  You really have to question whether elaborate manual processes add any value.

    I took a linguistics class in college.  I don't remember much (other than thinking the prof was a total clown), but I do remember that the evolution of a language is often just a constant erosion of sounds in a word until the word is easier to pronounce - especially words that are used often.  The evolution of a process should be the same way.  Anything that's clumsy or manually intensive without adding enough value to pay for itself should get all of its rough edges sanded off until it's easy to follow and smooth.

    Of course I've got that Pollyanna idea that the people that have to follow a process should be completely empowered to change, adapt, and modify that same process.  Bad, clumsy processes are almost always the product of somebody that doesn't have to dogfood their ideas.

  • Old Smalltalkers

    I say this out of no small degree of fondness because I've enjoyed working around ex-Smalltalkers over the years.  I'm fully aware of just how much debt we owe to the Smalltalkers, but... 

    The ultimate curmudgeon in all of classical literature is Nestor from the Illiad.  His part in Homer's story is largely to be the old, crusty guy who tells anybody who'll listen how much more heroic and manly his generation was compared to the ragtag gang trying to take Troy.  In positive terms, Nestor's role is also to inspire the younger warriors to great feats.  In the world of software development today, the role of Nestor is filled by old Smalltalkers.  Every single Smalltalker I've ever been around will go on for hours extoling the amazing abilities and technical accomplishments of the Smalltalk environment and community.  Any thing you've read about or started to use that makes coding more elegant was done better 20 years ago in Smalltalk.  Ruby?  Smalltalk lite.  DSL's?  Smalltalk did it.  Blocks, closures, and some functional programming mixed into your OO language?  Smalltalk did it.  Extension methods like what's coming in C# 3?  You guessed it (Objective C did too apparently.  Anybody know why Obj. C didn't really take off outside the Mac?  Just curious).

  • A Train of Thought - June 17, 2007 Edition

    I wrote some of this on a 5:40 AM train.  After this I'm not going to write any more commentary type posts on far too little sleep.  Besides little mismatched rants, I'm flushing out bits and pieces of blog drafts that just never escaped into the wild.  Think of this as a personal ablution to rid myself of negative thoughts from the past couple weeks - or a sacrificial anode to keep the metaphorical rust of ranting out of my posts for the next couple weeks.

    Just to let you know how far back this detritus goes back, I found this quote at the bottom of an unpublished post:

    By the way, the last thing I remember saying at work today was "Ohio State just has too much talent for Florida."  I hope my discussion about maintainable code is more on the mark than my game predictions tonight.

    Just in case you're wondering, I meant the college football championship in January.  The basketball championship in March was pretty easy to call.

     

    Embedded DSL's HOT, Programming with Xml, and Fun with Attributes NOT HOT

    Just adding to Roy's Hot/Not Hot blog post.  The above isn't completely true, but I wish it was.  I thought about this when I read through Ayende's not entirely complementary commentary on Acropolis.  I mostly agree with Oren on this one.  I'm perfectly fine with the Acropolis team adding all the designer support, as long as the levers are all exposed so I can wire up the MVP and service pieces with an embedded DSL of some sort instead of using the designer.   

    There's a quote from Martin Fowler that I like to paraphrase is "the only way to know how useful something can be is to overuse it then pull back."  We've hit that point a long time ago with "Programming with Xml" and I think we're well on our way with using attributes to describe behavior.  This whole idea that anything is automatically easier because it's configurable with Xml or a visual designer needs to be reexamined.  I'm much more inte