April 2008 Blog Posts

Using Composite Web Application Block Without Web Client Software Factory

The Web Client Software Factory is a great software factory from Microsoft Patterns & Practices that enables you to pretty easily make well-constructed enterprise ASP.NET applications that can be extended by downstream developers. The factory contains a lot of stuff - recipes, templates, and a lot of help to automate some common tasks - but the key item you'll find in there is the Composite Web Application Block.

The CWAB allows you to make modular web applications that come together at runtime to make a nice, seamless experience. It makes it easy to partition work to various teams but maintain a consistent experience across the application. It also enforces some nice Model-View-Presenter separation of concerns when using web forms. Well worth the effort to use.

The thing is, you may not always want the entire Web Client Software Factory package when using Composite Web Application Block. There are two primary reasons you wouldn't want the Web Client Software Factory in its entirety, both of which have to do with the associated guidance packages:

  • You don't want the stock guidance packages. That is, the recipes and templates and other automation items don't do what you want them to or are otherwise just something you don't want. Maybe it'd cost more to modify the guidance package to do what you want than it would be to just manually do the work. Maybe you don't want the dependencies that the guidance packages assume you want. Whatever the case may be, you don't want the guidance packages.
  • You don't want to deal with the developer environment cost. Having guidance packages that everyone has to use also means you have one more thing to install on every developer machine. When upgrades come around, it's not just dropping an assembly in a folder to take the upgrade. There's a cost associated with this, and you may not want to incur it.

Either way, you may not want the whole thing. What do you get by not taking it all?

  • Slightly ore complex setup. It's a little more effort to manually get a CWAB project going if you don't use the guidance packages. Not much worse, but this is a legitimate downside.
  • Manual control over everything. File placement, assembly breakdown, naming, etc. You could customize the guidance packages to do things your way, but it's not a 20-minute undertaking to do so. If you're not going to be adding pages or projects every single day, it's probably cheaper to just do it manually.
  • Fewer implied dependencies. The guidance packages assume you want the Patterns and Practices logging, security, and exception handling application blocks, so there's a lot of extra stuff that goes into the templates and such to support that. It can be a pain to rip all of this out if you don't want it. The only extra dependencies you have when you're using CWAB solo are CWAB proper and ObjectBuilder.
  • Easier upgrades. When a new version of CWAB comes out, it's an assembly update, not something that has to be installed on every dev box.
  • Easier ability to implement standard forms authentication. Out of the box, CWAB uses the security application block for locking down page access. If you just want standard location-based authorization it's easier to do it without the security application block in your way.

Here are some general steps to show you how to get CWAB working in your project without all of the guidance packages. It will help if you're familiar with using CWAB within WCSF before you try this out. (I have a sample later in this article that you can look at for a more concrete representation. I followed this general process in creating that sample.)

  1. Create a web application project.
  2. Add references to the Microsoft.Practices.CompositeWeb.dll and Microsoft.Practices.ObjectBuilder.dll.
  3. Add modules (class libraries). In most CWAB projects, there's a sort of default "Shell" module that corresponds to the main content of your site and registers most core services. Add at least this module. For each module you add:
    1. Add a reference to Microsoft.Practices.CompositeWeb.dll and Microsoft.Practices.ObjectBuilder.dll.
    2. Add a reference from the web application to the module.
    3. Add a module initializer class to the module. (A class deriving from ModuleInitializer.)
  4. Add a Global.asax that derives from Microsoft.Practices.CompositeWeb.WebApplication.
  5. For the Default.aspx page (which comes for free with your web application project)...
    1. Break the page up into Model-View-Presenter format with the presenter and view interface in your "Shell" module.
    2. Update the page namespace to match the namespace the presenter and view interface are in.
    3. Update the page to implement the view interface.
    4. Update the page to derive from Microsoft.Practices.CompositeWeb.Web.UI.Page.
    5. Add a Presenter property to the page with a [CreateNew] ObjectBuilder attribute on it.
    6. Add the page to the "Shell" module initializer's site map registration.
  6. Rinse and repeat for additional pages - put the presenter and view interface in the proper "business module" and implement the interface on the page.

There are a lot of things you can do to make this way, way easier.

  • Create abstract generic "View" and "MasterPage" base classes. There's a lot of common "template" sort of stuff (like the "Presenter" property on every single web page) that can be removed by creating some abstract generic classes and deriving from those instead.
  • Create abstract module initializer classes for business modules and foundational modules. Every business/foundational module initializer is almost identical. You can make it easier to create initializers if you have some base classes that have abstract methods you're forced to implement.

To get standard location-based authorization working with the site map, you'll also need to create a custom SiteMapProvider to use in place of the one that comes with Composite Web Application Block. The reason you'll need that is because the out-of-the-box version trims by security application block settings. To bypass that and use standard location-based auth, you'll need a custom provider.

It sounds like a lot, but keep in mind it's one-time work and once you've got it set up, it's not all that bad. To get you started, I've got a sample project you can download and see it in action. You'll need to get the Web Client Software Factory because you'll need the assemblies that come with it (I didn't include them in my sample project). Drop them into a specific folder in the sample project and you should be good to go.

Of interest in my sample:

  • The "Framework" module has some example abstract base classes for views and initializers.
  • The "Navigation" module has a service that helps you locate existing nodes in the site map and contribute to them - something the CWAB doesn't come with out of the box.
  • I called my "Shell" module "Core" to make sure there was no reliance on the assembly name "Shell."
  • The "Core" module has a location-based authorization SiteMapProvider example.
  • The sample master pages and style sheets are the ones that come with the WCSF default site template.

The sample is exactly that - a sample. It's not really tested (it works in the context of the sample, though) and I don't offer you any guarantees that this will work for you and be totally bullet-proof. Your mileage may vary, no warranty expressed or implied, etc.

[Download CwabSolo.zip (48K)]

GTA4 In The House

GTA4 Unboxed - Click for photos.Picked up my copy of GTA4 just now. I'm off next week to play all week long and I totally can't wait. Here are some photos of the unbox at my desk.

Two Minute WF: WorkflowInstance

In this Two Minute WF, I'm going to tell you about WorkflowInstance.

This is a really simple one: A WorkflowInstance is - wait for it - a single instance of a workflow. Yes, it really is that simple. You pick your workflow type, fill in the activities it'll use, and you have a workflow definition. Once you have the definition, you instantiate it and start it running. It's sort of like defining your class/type and then newing one up. For objects it's like this:

MyCustomType myVar = new MyCustomType();

For workflows, it's like this:

using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
  AutoResetEvent wh = new AutoResetEvent(false);
  workflowRuntime.WorkflowCompleted +=
    delegate(object sender, WorkflowCompletedEventArgs e) {wh.Set();};
  workflowRuntime.WorkflowTerminated +=
    delegate(object sender, WorkflowTerminatedEventArgs e) {wh.Set();};
  WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(MyCustomWorkflowType));
  instance.Start();
  wh.WaitOne();
}

In the example, I not only create an instance of my custom workflow type, but I also start it running. It's a little more complex than just creating a new object, but it's not that much worse.

The WorkflowRuntime is responsible for instantiating workflows and starting them running. Since workflow instances run on a different thread than the main program, I'm using an AutoResetEvent to do thread synchronization - we don't want to end the program or dispose of the WorkflowRuntime until the WorkflowInstance has had a chance to complete its run.

Something to watch for when you're working in a larger environment with lots of instances - you only get one WorkflowRuntime for a given AppDomain. What that means is the WorkflowCompleted and WorkflowTerminated events are for all WorkflowInstances - you don't get one for each instance. Be careful when subscribing to these events when you just want info on a single instance. If you forget to unsubscribe from the event and the event subscriber goes out of scope, you may have a memory leak on your hands. (The Garbage Collector won't clean up the now-unreferenced event subscriber because there's still one reference to it - the subscription to the global WorkflowRuntime event.)

posted @ Tuesday, April 29, 2008 9:37 AM | Feedback (0) | Filed Under [ .NET ]

Jonathan Coulton at Mission St. Theater

Jonathan Coulton plays the Mission St. Theater - Click for PhotosJenn and I saw Jonathan Coulton with Paul and Storm last night at the Mission St. Theater in a sold out show.

It was awesome.

We got there about an hour before the doors opened and it's good we did because the line was already pretty long. By the time the doors opened, it was around the corner and well down the block.

As we were waiting in line, Jonathan, Paul, and Storm all walked past to get to the front door... and then walked right by again to head to the artist entrance.

We got great seats right up front with no one blocking our view. Paul and Storm opened and we were very pleasantly surprised - I'd never heard them before, but they've made new fans of us. They played for about an hour and then there was a break before Jonathan Coulton came on.

When he did come on, it was great. He really played the crowd well and the small venue added to it. He sang all of the great ones - Re: Your Brains, Still Alive, Code Monkey, Skullcrusher Mountain - and a bunch of others, also great. During Re: Your Brains, the audience sang the zombie part. Gotta love it.

It was sort of a crazy crowd. Great people, everyone really wanted to be there, but... well, only at a Coulton show could I look down the line and see people reading the Learning Perl book. A wonderfully geeky mix of folks.

I posted some pictures on Flickr of the show. They're not the most exciting pix because the show wasn't really flashy, but they're decent and show you how close we were.

I ended up getting the entire Thing a Week box set and the Smoking Monkey album. Support your favorite artists, right? Another cool surprise - the Thing a Week box set was signed and numbered inside. Awesome.

We'll definitely be going again when he comes back to town.

InnoTech Presentations Posted

The presentations from the InnoTech PDX conference I spoke at have been posted. You can get my "Unit Testing with Typemock" presentation as well as the demo code from there.

posted @ Thursday, April 24, 2008 11:49 AM | Feedback (0) | Filed Under [ .NET ]

Canon PIXMA MX850 All-In-One: Probably a Great Printer, Horrible Scanner

Based on my previous all-in-one experience with the HP C7280, when I brought the Canon PIXMA MX850 home, the first thing I did after I installed it was to try out a scan. I didn't print, I didn't copy, I just scanned.

Freaking garbage.

Not as bad as the HP C7280, mind you, but still pretty bad. I tried a book cover and two different CD covers. All of them came out with horrible Moire patterns and pixel artifacts.

I never printed a single page (other than the printer head calibration). It's already in the box to be taken back.

I've learned something, but I'm not sure what.

  • Should I not trust all-in-one units because their scan capabilities will be mediocre at best compared to a dedicated scanner?
  • Should I not trust units with CIS scanners (as both the HP and Canon had) and look for something with a CCD scanner?
  • Should I not trust units that can attach over the network and/or USB? (Though the connection didn't matter when I tried it out both ways, so I doubt it's this one.)

Anyway, back to square one.

Getting The Most From Twhirl

I'm a Twitter user, but it wasn't always like that. The problem is, Twitter really only seems to be useful if you have a Twitter client. The web site interface they provide is cumbersome, and if you've only used it over SMS or IM, you're missing out on a far richer experience.

I started out using Snitter and really liked it, but there were a few features missing (like the ability to follow someone right from the client) that I wanted, so I tried twhirl. It's pretty cool. The only thing I didn't like about it is that you have to customize the defaults a bit to really get the most out of it. Here's what you have to do to get the most from twhirl:

Turn off "prefix tweets with sender's name." This is in the configuration, on the "Visual" tab. The sender's name already appears in some smaller meta-text below each post, so prefixing the tweets with the sender's name just eats up screen space.

Turn off "mark received tweets as new." This is also in the configuration, on the "Visual" tab. Unless you follow less than 10 people or you have more time on your hands than you know what to do with, you're probably not going to be reading Twitter the same as you read email. Twitter is like standing in a convention hall where everyone is talking to everyone else. You'll probably miss some tweets, you might hear bits and pieces of a conversation, and that's OK. Turning this option off will stop you from seeing an annoying little "light" on each tweet you haven't read.

Set the opacity to 100% when inactive. Again, in the configuration, on the "Visual" tab. It's really annoying to have a 65% opaque window scrolling tweets when you're doing something else. It's like seeing something in your peripheral vision that you can't quite get to focus. Turn this up to 100% so there's something concrete to glance over to when you're working on something else.

Customize your color scheme. This can be as easy or as difficult as you want it. The default aqua sort of color scheme is just painful. You can very easily select a new color scheme from the Accounts window on the "Colors" tab. I recommend one of the black schemes, but check it out and you can see a little preview image of each one and choose your own.

The other option you have is to create your own color scheme. As of version 0.7.5, this isn't an "officially supported option," but it's still simple.

To create your own scheme:

  1. Go into the twhirl "colorschemes" folder (C:\Program Files\twhirl\colorschemes) and you'll see a bunch of XML files in there. The names of these files roughly correspond to the names of the available twhirl color schemes.
  2. Find one that is reasonably similar to what you want yours to look like and copy it.
  3. Rename the copy to a short/small version of the name of your new color scheme - for example, if your color scheme is "Navy Blue" you might call the file "navyblue.xml" or something.
  4. Open the copy in a text editor. The XML is pretty self explanatory. Read through it to familiarize yourself, then...
  5. Update the <title>, <version>, <author>, and <date> information. The title is what will appear in twhirl.
  6. In the <colors> section, you'll see all sorts of available options. The value in each tag is a hex color number. Use a hex color picker or your favorite paint tool to update the colors.
  7. When you think you have it right, save your changes and exit twhirl. Make sure it's not running - just closing the chat or the accounts window won't do it. You have to click "Exit twhirl" from the accounts window.
  8. Restart twhirl and switch to your new color scheme. If you need to make adjustments, switch to a different color scheme before exiting twhirl. (I had trouble where it seemed to cache the previous color scheme values if I didn't do that.)

When I created my custom scheme, I wanted to address the following issues:

  • Easy readability - I'm not a dark-background-light-text person, so I picked a white background with black text.
  • "Standard" link color - The web has sort of conditioned people (me) to think link == blue. Not creative, but I don't have to think about what's clickable and what's not.
  • Ability to locate relevant tweets - I want to easily be able to scroll through and find tweets from me and tweets to me (both replies and direct messages).
  • Nothing too ridiculously garish - I was limited a bit by the inflexibility of the theme options, but basically I tried for something that wasn't, like, "high contrast" or something overtly offensive to my rods and cones.

My custom scheme looks like this:

Illig custom twhirl color scheme

And you can download it here if you like. (Unzip the file into your twhirl colorschemes directory. The XML file inside is the color scheme.)

Overall, twhirl is pretty good. Snitter is a little better from a style flexibility perspective, and if it gets updated to have some of the features I like, I'll probably switch back. On the other hand, if twhirl can give me some additional style flexibility, I'll be totally won over.

Great Drummer Stool

I play fake drums in Rock Band and have a great time with it. Problem is, my dining room chairs aren't great for drumming. They're a little low and generally bulky compared to what I need when I'm rocking out. I ended up finding the "Vitamin" stool at Ikea and it's perfect.

  • Adjustable height.
  • Comfortable seat.
  • Tolerant of the need to lean forward or backward (at least if you're playing on carpet) - underneath the bottom is sort of angled on the edges.

Plus, it's pretty reasonably priced. If you're looking for a good drummer stool, grab yourself one of these.

ASP.NET Testing with Ivonna

[Hmmm, that sort of sounds like a PBS show or something. Hehehe.]

The folks over at Typemock passed a link along to me an interesting new project called Ivonna. It's an ASP.NET testing framework (currently in beta) that runs on top of Typemock Isolator. It lets you run unit tests against web forms apps without a web server and access the controls and such right from your unit test.

Rather than explain it in long prose, let me just show you an example.

Say you have a web form that takes in two numbers and adds them together. Yes, your typical overused calculator application. The page probably looks like this:

<%@ Page Language="C#" Inherits="System.Web.UI.Page" %>
<html>
  <head runat="server">
    <title>Calculator</title>
  </head>
  <body>
    <form id="form1" runat="server">
      <table>
        <tr>
          <td>First number:</td>
          <td><asp:TextBox ID="FirstNumber" runat="server"/></td>
        </tr>
        <tr>
          <td>Second number:</td>
          <td><asp:TextBox ID="SecondNumber" runat="server"/></td>
        </asp:TableRow>
        <tr>
          <td ColumnSpan="2">
            <asp:Button
             ID="SubmitButton"
             runat="server"
             Text="Calculate"
             OnClick="SubmitButton_Click" />
          </td>
        </tr>
        <tr>
          <td ColumnSpan="2" HorizontalAlign="Right">
            Total: <asp:Label ID="Sum" runat="server"/>
          </td>
        </tr>
      <table>
    </form>
  </body>
</html>
<script runat="server">
void SubmitButton_Click(object sender, EventArgs e)
{
  this.Sum.Text = (
    Double.Parse(this.FirstNumber.Text) +
    Double.Parse(this.SecondNumber.Text)
    ).ToString();
}
</script>

A couple of text boxes, a submit button, and a label to take in the result. You want to test that entering the numbers into the boxes and clicking the button actually puts the right text into the label. Check this out - it doesn't get much simpler:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using Ivonna.Core;
using Ivonna.Framework;
using NUnit.Framework;
using TypeMock;

namespace UnitTests
{
  [TestFixture]
  [VerifyMocks]
  [RunOnWeb(@"C:\Path\To\WebApplication", @"/")]
  public class DefaultPageTestFixture : WebFixture
  {
    [Test]
    public void AddTwoNumbers()
    {
      TestSession session = this.InitSession();
      Page page = session.GetPage("Default.aspx");
      TextBox firstNumber = (TextBox)page.FindControl("FirstNumber");
      firstNumber.Text = "15";
      TextBox secondNumber = (TextBox)page.FindControl("SecondNumber");
      secondNumber.Text = "20";

      page = session.ProcessPostback("SubmitButton");
      Label sum = (Label)page.FindControl("Sum");
      Assert.AreEqual("35", sum.Text);
      this.EndSession();
    }
  }
}

That looks a lot like ASP.NET codebehind, doesn't it? Familiar syntax? And you didn't have to automate a browser, fire up a web server instance, or anything. Let's walk through what's going on in that test:

  1. There are test attributes to indicate this is an NUnit test fixture, I want to verify my Typemock mocks, and this is a web fixture. I specify the physical and virtual paths to the web application so the "navigation" works correctly.
  2. I derive my page test fixture from an Ivonna base test fixture.
  3. In the test...
    1.  Initialize my web "session."
    2. Do the initial page GET. Again, this isn't actually doing web communication.
    3. Do a standard FindControl call on the page to get references to the textboxes I want to populate in the form.
    4. Set the values in the textboxes.
    5. Tell the page I want to do a postback and provide the ID of the button causing the postback. (I could also have gotten a reference to the button using FindControl and passed in the reference.)
    6. Use FindControl again to get the label that contains the result.
    7. Verify the result is what I expected.
    8. End the web "session."

This is easier by far than trying to mock out HttpContext and such. Granted, it's still pretty early and there's a lot of room for improvement, and I don't think it'll entirely replace UI automation testing, but this could help out a lot in catching bugs early and running more UI-based tests without actually automating UI. Go check it out and see what you think.

Quick Start for Mocking with Typemock Isolator

Introduction

This quick start gets you up to speed on the basic functionality of Typemock Isolator. As you go through it, note:

  • While some basic unit testing will be reviewed, this is not a quick start for NUnit or unit testing in general, so proper test design and specifics on NUnit usage will not be addressed.
  • The quick start shows usage of the Enterprise features of Typemock Isolator. While all of this is possible in the community edition, the alternate mechanisms for accomplishing things won't be discussed.

At the very end are some take-away points and additional resources. Work through the quick start, do the exercises, and at the end check out the take-away points so you'll have something to move forward with.

You can get the source for the finished solution here (minus the answers to the exercises - that's for the reader), but it's recommended you create your solution and walk through the work and not just get the finished deal: [Download Source - TypeMockQuickStart.zip]

Required Tools

You'll need to have the following to work through the quick start:

Visual Studio 2008, Typemock Isolator, and TestDriven.NET get installed on your local developer machine. NUnit should be in an accessible location but doesn't necessarily have to be installed. Get the latest available versions.

Create Test Solution

You'll need a place where you can run through these exercises, so...

  1. In Visual Studio, select "File -> New Project..."
  2. In the "New Project" dialog...
    1. In the tree view on the left, under "Visual C#" select "Windows."
    2. In the "Templates" section on the right, select "Class Library."
    3. Give your libary a name like "TypeMockQuickStart."
  3. In the Solution Explorer, in your new class library...
    1. Delete "Class1.cs" - we'll add more appropriately named classes later.
    2. Add references to NUnit and Typemock Isolator.
      1. Right-click the "References" folder and select "Add Reference..."
      2. In the .NET tab, select "Typemock Isolator for .NET 2.0" and click OK.
      3. Right-click the "References" folder and select "Add Reference..."
      4. Reference NUnit. If you've installed NUnit, select the NUnit Framework assembly from the .NET tab; if you're accessing NUnit from a known location, go to the Browse tab and find "nunit.framework.dll" and add a reference to that.

Patterns

This section discusses basic patterns you'll need to understand while working with unit testing and mocking.

Unit Tests: Setup, Execute, Assert

The basic pattern for a unit test is "Setup, Execute, Assert":

  • Setup: Set up the test environment and the code that you're testing. This usually involves initializing some variables, instantiating your class, or setting up some configuration files that the code being tested needs.
  • Execute: Execute the code being tested.
  • Assert: Check to make sure that what you just executed had the desired behavior.

To examine this pattern, set up a simple class that can be tested and perform some unit tests on it.

  1. Add a class called Calculator. Make it public.
  2. In the Calculator class, add a method with this signature that adds two doubles (a + b): public double Add(double a, double b)
  3. Fill in the body for the Calculator.Add method.
  4. In the Calculator class, add a method with this signature that divides two doubles (a / b): public double Divide(double a, double b)
  5. Fill in the body for the Calculator.Divide method. If "b" is zero, throw a DivideByZeroException.

Now you have a simple class to test, let's add a test fixture for it.

  1. Add a class called CalculatorFixture. Make it public.
  2. Add an NUnit [TestFixture] attribute to CalculatorFixture. This is how you tell NUnit and TestDriven.NET that this class contains unit tests.

You now have a class to test and a fixture to contain your tests. Add a test for the Calculator.Add method.

  1. In your test fixture class, add a public void method that takes no parameters called "AddTwoPositiveNumbers": public void AddTwoPositiveNumbers()
  2. Add an NUnit [Test] attribute to the AddTwoPositiveNumbers method. This is how you tell NUnit and TestDriven.NET that this is a test to run.
  3. Follow the "Setup, Execute, Assert" pattern to create your test.
    1. Setup: Create an instance of the Calculator class.
    2. Execute: Call the Add method on the instance with two positive numbers of your choosing.
    3. Assert: Verify that it returned the expected result.

Your test fixture will look something like this:

[TestFixture]
public class CalculatorFixture
{
  [Test]
  public void AddTwoPositiveNumbers()
  {
    // Setup
    Calculator calc = new Calculator();

    // Execute
    double result = calc.Add(3, 7);

    // Assert
    Assert.AreEqual(10, result);
  }
}

Exercise

Add more tests.

  • Test the Add method:
    • Test adding of two negative numbers.
    • Test adding a number to zero.
  • Test the Divide method:
    • Test dividing one positive number by another.
    • Test dividing by zero (don't catch the exception - use the NUnit [ExpectedException] attribute on your test method).

Notice how the pattern is basically the same? You do some initialization, run some code, and assert that the result is what you expected. You see a slight deviation from that pattern when testing for expected exceptions, but it's still basically doing an assertion, just expressed differently.

Mocking: Record, Playback, Verify

The basic pattern for mocking an object is "Record, Playback, Verify":

  • Record: Tell the mocking framework what you're about to do on the mock object.
  • Playback: As you're executing the test, the mocking framework "repeats" what you recorded.
  • Verify: Check to make sure that all the mocks you set up were called correctly.

This parallels the unit test "Setup, Execute, Assert" pattern. Part of your setup is to record your mocks; part of execution is playing back your mocks; part of assertion is verifying your mocks.

Add a new method to the Calcuator class that has additional complexity. We'll use mocking to test this method:

public double AddThenMultiply(double a, double b, double c)
{
  double addResult = this.Add(a, b);
  double multiplyResult = addResult * c;
  return multiplyResult;
}

Notice in this method that we're calling the Add method (which we've already tested) and performing some additional custom logic that we need to test. This sort of thing is perfect for mocking. We don't want to re-test the Add method; we want to isolate the logic in the new method and just test that. Let's add a new fixture with tests that use Typemock Isolator to isolate the new logic.

  1. Add a class called CalculatorMockingFixture. Make it public.
  2. Add an NUnit [TestFixture] attribute to CalculatorMockingFixture.
  3. Add a Typemock Isolator [VerifyMocks] attribute to CalculatorMockingFixture. This tells Typemock Isolator to automatically do the mock verification part of the test for you when the test is complete. It saves you from having to manually verify in every test.

The empty fixture should look like this:

[TestFixture]
[VerifyMocks]
public class CalculatorMockingFixture
{
}

Now we're ready to add a test. In the CalculatorMockingFixture add a test method called MultiplyPositiveAddResult. Here is the method body:

[Test]
public void MultiplyPositiveAddResult()
{
  Calculator calc = new Calculator();
  using (RecordExpectations recorder = RecorderManager.StartRecording())
  {
    double dummy = calc.Add(0, 0);
    recorder.Return((double)15);
  }
  double result = calc.AddThenMultiply(5, 10, 20);
  Assert.AreEqual(300, result);
}

There's a lot happening here, so let's look over it:

  1. The Calculator object we're going to test gets instantiated.
  2. A using block is created where a new RecordExpectations object is created. This is a very common block you will see in Typemock Isolator usage that says, "Everything in this block is fake! Record it and get ready to play it back." Inside that block...
    1. We're calling the Add method on the Calculator. Notice that we're passing 0 for both parameters. The reason for this is that the Add method really isn't getting called, so it doesn't matter what we pass. The important part of this is that we're telling the recorder, "I'm going to call the Add method." We don't even really care what we name the variable where we store the result because we'll never use it - hence, we'll just call it "dummy."
    2. We tell the recorder the value we want Add to return - in this case, we want it to return 15. We don't care what gets passed in, the first time Add gets called, we want 15 to come back.
  3. The using block closes, meaning we're done recording for now. Time for playback.
  4. We call the AddThenMultiply method and get the result.
  5. We assert that we got the correct result.

What did mocking get us? Try this: change this line:

double result = calc.AddThenMultiply(5, 10, 20);

To this:

double result = calc.AddThenMultiply(500, 1000, 20);

Now run the test again. Notice how it still passes? Why is that? That's mocking in action. If you follow the call stack, you know that the first thing the AddThenMultiply method does is call the Add method. Typemock Isolator sees that call to Add and doesn't actually let Add execute - instead, it returns the value we told it to return. In this case, we'll get 15 back.

Exercise

Do some experimentation...

  • What happens if you call Add a second time in your test? Try adding a call to calc.Add after the AddThenMultiply call.
  • Why does that happen?
  • Can you set it up so the recorder returns 15 for the first call to Add but 25 for the second call?

Practical Application

Once you've gotten your first mock down and get the patterns, the next question is, "How can I actually use this in my job? I'm not writing Calculator classes all day." The benefit of mocking is to isolate the code that you're testing - that includes isolating it from the behavior of the .NET framework and other third-party dependencies. In this section you'll walk through an example of isolating your code from .NET proper and look at some additional mocking verification that can be done to ensure your code is calling the framework correctly.

Add a Class That Uses Configuration

To experiment with isolation from .NET, we'll add a new class. This class will make use of the .NET configuration system to read a value from configuration and perform an action based on that.

  1. Add a reference to the System.Configuration assembly.
  2. Add a class called ConfigReader. Make it public.
  3. Add a public method called AppendValueToSetting that takes in a string and returns a string: public string AppendValueToSetting(string valueToAppend)
  4. Fill in the AppendValueToSetting method:
    1. Read the AppSettings key "configReader" and store the result.
    2. Append the contents of the valueToAppend parameter to the end of the value from configuration.
    3. Return the concatenation results.

It should look like this:

public class ConfigReader
{
  public string AppendValueToSetting(string valueToAppend)
  {
    string setting = ConfigurationManager.AppSettings["configReader"];
    string result = setting + valueToAppend;
    return result;
  }
}

Test Cases

Consider what you need to test about this method:

  • What happens if the setting isn't found?
  • What happens if the setting is empty?
  • What happesn if the setting is found?

Now consider: It reads from the App.config file - how do you change that between tests? Is that even a good idea?

Again - mocking to the rescue.

Isolate Yourself From the Framework

  1. Add a test fixture for testing this class. Call the fixture ConfigReaderFixture and include both the [TestFixture] attribute and [VerifyMocks] attribute.
  2. Add a unit test to the fixture. Call it SettingFound - we'll test what happens when the setting is correctly read from configuration.
  3. In the test...
    1. Create an instance of ConfigReader.
    2. Create a recorder block. Inside the recorder block...
      1. Read the ConfigurationManager.AppSettings["configReader"] key.
      2. Tell the recorder to return the value "readFromAppSettings".
    3. Call the AppendValueToSetting method and pass in "PassedInFromTest".
    4. Assert that the value you get back is "readFromAppSettingsPassedInFromTest" - the result of concatenating the two strings.

The test will look like this:

[Test]
public void SettingFound()
{
  ConfigReader reader = new ConfigReader();
  using (RecordExpectations recorder = RecorderManager.StartRecording())
  {
    string dummySetting = ConfigurationManager.AppSettings["configReader"];
    recorder.Return("readFromAppSettings");
  }
  string result = reader.AppendValueToSetting("PassedInFromTest");
  Assert.AreEqual("readFromAppSettingsPassedInFromTest", result);
}

Notice how you didn't actually have to put anything in App.config - you don't really want to re-test the functionality of the .NET framework, you just want to test that your code is correct.

Exercise

Take this to the next step...

  • Add a test where the app settings value is null to simulate what happens when it's not found.
  • Add a test where the app settings value is empty string to simulate when the key is there but has an empty configured value.

Verifying Mock Behavior

Try this: Go to your ConfigReader class and modify this line:

string setting = ConfigurationManager.AppSettings["configReader"];

To be this:

string setting = ConfigurationManager.AppSettings["theWrongKey"];

Now run your tests - they all still pass. Why?

As mentioned earlier, Typemock Isolator will, by default, just notice which methods and properties you're using, not what the values of parameters are. Sometimes you'll want to make sure that not only does the third-party dependency return an expected/recorded result but also that your code is passing in the proper parameter values. In this case, you want to not only make sure that you're getting an expected value from the configuration system but also that your code is asking for the value you think it's asking for. You'll want the recorder to "check arguments."

Leave the wrong config key in your ConfigReader class - we'll catch that it's wrong inside the unit tests.

In the SettingFound test, in your recorder block immediately after the call to ConfigurationManager.AppSettings, tell the recorder to check arguments:

[Test]
public void SettingFound()
{
  ConfigReader reader = new ConfigReader();
  using (RecordExpectations recorder = RecorderManager.StartRecording())
  {
    string dummySetting = ConfigurationManager.AppSettings["configReader"];
    recorder.CheckArguments();
    recorder.Return("readFromAppSettings");
  }
  string result = reader.AppendValueToSetting("PassedInFromTest");
  Assert.AreEqual("readFromAppSettingsPassedInFromTest", result);
}

That tells the recorder that you want to ensure the arguments in the mocked statement are correct. In this case, the argument is the string "configReader" that gets passed to ConfigurationManager.AppSettings. Now run the tests: The SettingFound test fails with an exception like this:

TestCase 'TypeMockQuickStart.ConfigReaderFixture.SettingFound'
failed: Typemock Isolator.VerifyException :
Typemock Isolator Verification: Call to System.Collections.Specialized.NameValueCollection.get_Item() Parameter: 1
 expected: <"configReader">
  but was: <"theWrongKey">

Typemock Isolator caught that the wrong parameter was passed - the one in the test ("configReader") was expected, but your production code used the wrong value ("theWrongKey"). Fix the ConfigReader class back to the correct settings key and your test will pass again.

Mocking Instances

Once you get past the simplest of cases, you start needing to mock specific instances of classes and sometimes you need to mock methods on instances that get created inside non-test code. Typemock Isolator can do both of these things.

Mocking a Current Instance

This exercise will show you how to create an instance of an object where the constructor of the object is mocked and you control the entire life of that object.

Add a new class to your project. This class will use the Calculator class you added earlier. First, add a couple of constructor overloads to your Calculator class:

public class Calculator
{
  private bool _allowAdd;
  public Calculator() : this(true) { }
  public Calculator(bool allowAdd)
  {
    this._allowAdd = allowAdd;
  }
  // Add, Divide, and AddThenMultiply methods omitted for clarity.
}

Now update the Calculator.Add method so if the _allowAdd member variable is false, the Add method won't run:

public double Add(double a, double b)
{
  if (!this._allowAdd)
  {
    throw new InvalidOperationException("Add operation is not allowed.");
  }
  return a + b;
}

Running your tests, they should all still pass. Notice the default value for allowing the Add operation is true and it's set in the default constructor. Now in your CalculatorMockingFixture test fixture, add a new test:

[Test]
public void SkipConstructor()
{
  Calculator calc;
  using (RecordExpectations recorder = RecorderManager.StartRecording())
  {
    calc = new Calculator();
  }
  calc = new Calculator();
  double result = calc.Add(2, 2);
  Assert.AreEqual(4, result);
}

This test runs the constructor for the object inside the recorder block - that means the constructor itself will be mocked. In this case, think about what that means - the default value for an uninitialized Boolean is false, so the _allowAdd value, which normally gets initialized to true in the default constructor, will remain false and won't let the Add operation run.

Run the test and the test will fail:

TestCase 'TypeMockQuickStart.CalculatorMockingFixture.SkipConstructor'
failed: System.InvalidOperationException : Add operation is not allowed.

You can fix the test so it passes by adding an [ExpectedException] attribute to the test and expecting an InvalidOperationException.

Usually constructor logic is more complex than this - it might read from configuration, try to initialize a file in the filesystem, or do some other actions that you may want to control. In cases like these, you may need to mock the constructor for the object.

Exercise

Add a test where you mock the constructor logic but also test the AddThenMultiply method. What does that look like? How does it differ from the original test you ran with AddThenMultiply?

Mocking a Future Instance

This exercise will show you how to set up expectations on an object that gets created in code you don't control.

Add a new class called BackwardsCalculator to your project. The constructor of the BackwardsCalculator class will create an instance of Calculator and hang onto it. A method ReverseAdd will perform an add operation using the Calculator and reverse the string value of that. The BackwardsCalculator class looks like this:

public class BackwardsCalculator
{
  private Calculator _calculator;
  public BackwardsCalculator()
  {
    this._calculator = new Calculator();
  }
  public string ReverseAdd(double a, double b)
  {
    string forward = this._calculator.Add(a, b).ToString();
    string reversed = new string(forward.ToCharArray().Reverse().ToArray());
    return reversed;
  }
}

If you feed in 10 and 25 to the ReverseAdd method, you'll get "53" returned: 10 + 25 is 35, reverse 35 is 53.

Notice how the BackwardsCalculator constructor is creating a Calculator but you don't get a chance to insert a mock yourself. That's okay - you can still use mocks to mock out the call to Calculator.Add so you're isolating your code.

  1. Add a test fixture for testing this class. Call the fixture BackwardsCalculatorFixture and include both the [TestFixture] attribute and [VerifyMocks] attribute.
  2. Add a unit test to the fixture. Call it ReverseAddPositive - we'll test two positive inputs.
  3. In the test...
    1. Create a recorder block. Inside the recorder block...
      1. Create an instance of the Calculator class.
      2. Call the Add operation and pass in two known values.
      3. Check the arguments on the Add operation to make sure you're getting called with the expected parameters.
      4. Return the known good result.
    2. Create an instance of BackwardsCalculator.
    3. Call the ReverseAdd method and pass in the parameters you decided on in the record block.
    4. Assert that the value you get back the reversed sum of the two numbers.

The test will look something like this:

[Test]
public void ReverseAddPositive()
{
  using (RecordExpectations recorder = RecorderManager.StartRecording())
  {
    Calculator dummyCalc = new Calculator();
    dummyCalc.Add(10, 20);
    recorder.CheckArguments();
    recorder.Return((double)30);
  }
  BackwardsCalculator bCalc = new BackwardsCalculator();
  string result = bCalc.ReverseAdd(10, 20);
  Assert.AreEqual("03", result);
}

By adding the constructor call to the mock recorder block, we're saying, "Mock the next instance of this object that gets created and set these expectations on that object." When we instantiate the BackwardsCalculator after the recorder block, the mocking framework goes into playback mode and mocks the creation of the Calculator in the BackwardsCalculator constructor.

Exercise

  • If Add was doing more than just adding, this would be perfect for isolating our code. Add is a simple method, though. Look at the CallOriginal method on the recorder and see if you can get a test to pass where you're checking arguments but actually calling a live version of the Calculator.Add method.
  • The ReverseAdd method is using LINQ to reverse the string. Try mocking the LINQ Reverse or ToArray statements.
  • Look at the WhenArgumentsMatch method on the recorder. It lets you conditionally mock a statement based on the arguments that get passed into a method. Can you set up the mock so it only runs when the arguments match what is getting passed in?

Advanced Mocking

Mocking lets you isolate yourself from a lot of common situations, including:

  • Class factories - Instantiate a class based on a configured value. Isolate yourself from configuration when testing the factory or isolate yourself from the factory when testing code that uses the factory.
  • Third-party dependencies - Components from external vendors. Isolate yourself from the behavior of the dependency so you're not testing the component, you're testing your code.
  • .NET framework - Built-in framework classes. Isolate yourself from the internal workings of the framework and test just how you're using it.
  • Legacy API - Code you have to interact with on legacy systems. Isolate your interaction code from the legacy system so you're not testing the system.

There are other cases where you might need to use Typemock Isolator, too, like adding tests for an API that was already written and can't change. You can mock lots of things that can make testing tricky...

  • Fields.
  • Static methods/properties.
  • Private methods/properties.
  • Sealed classes.

Take-Away

If you forget everything else, remember these rules of thumb:

  • Record, Playback, Verify.
  • If it's in a mock recorder block, it's not actually running - it's recording to be played back later, like a tape recorder.
  • Only mock what you need. You can get into some crazy situations by mocking too much, and you might end up in a spot where you're just testing your mocks and no actual code.
  • Just because you can mock it doesn't mean you should. For example, Typemock Isolator can mock fields, but you should really stop and look at what you're mocking before you get too deep. Knowing too much about the internal implementation of a class will make your tests very brittle if anything has to change.
  • You still need to design your application with good principles. Typemock Isolator enables you to test poorly designed code, but that's not a green light to stop proper software design.

Additional Resources

The Typemock Learn page has a great set of resources, including:

  • API documentation
  • Examples
  • Multimedia
  • Cheat sheets
  • FAQ

The Cheat Sheets are particularly helpful - one-page references you can print off and use while you're working.

If you use Snippet Compiler, you can experiment with Typemock Isolator using a special template for Snippet Compiler.

HP C7280 All-in-One: Great Printer, Horrible Scanner

Not quite a month ago, I bought an HP C7280 All-in-One scanner/fax/copier/printer over at the Buy More. I chose an all-in-one because my desk at home was starting to look like a dot-com-startup server room with all of the various pieces of equipment crowding around. The printer died and I sort of wanted to upgrade from my old HP ScanJet 5P (SCSI-based) scanner, so I figured now was the time.

Got it home and it printed beautifully. Like, even on "normal" quality, the print output really was gorgeous. Put a 5" x 7" photo on it and did a photo reprint at 4" x 6" and it not only perfectly scaled the photo down but did a borderless reprint on photo paper that looked as good as the original. Very impressed. To top it off, it was connected entirely via ethernet, so I didn't have to have a print server or anything sharing the printer so the laptop could access.

It was about a week after I had it before I tried to do a scan - a CD album cover so I could attach the album art in iTunes.

Horrible. Like, really horrible.

Here's a snippet of the Juno soundtrack cover. When you look at the cover with the naked eye, it looks nice, crisp, smooth. The edges of the orange stripes are sharp. The light gray shading is a solid color. The letters, while done with a hand-drawn style, have hard edges. Not at all how the scan comes out.

Bad scan of the Juno CD cover.

Look at the scan - the edges of the orange stripes are actually fuzzy. There's pixelation, almost like a halftone, in the gray shading. The edge of the "J" there looks like it was drawn with a dull colored pencil, which isn't even close to the way the cover actually looks.

This is how every scan turned out. Colors that appear solid on paper become spotty. I had one weird instance where I scanned a large area of solid blue and the scan came out with Moire patterns in it. To add to the weirdness, this only really happened with printed materials. If I scanned a photo, it would come out decent.

I tried different resolutions, different color depths, different sharpness settings, different color/brightness settings, different OSes (Vista and XP), different scanning programs, different versions of the drivers... no luck.

I spent two weeks going back and forth with HP support on it and they claim (rightly so) that since copies looked good, there was nothing wrong with the hardware. We then spent literally hours uninstalling and reinstalling drivers, adding and removing HP bloatware... all to no avail. I'm about three days away from my 30 day return limit and I'm taking it back tonight.

I'll be looking at Canon or Epson. Sorry, HP. I'm done.

Infrared to Bluetooth Converter for PS3

As I'm thinking about getting a PS3 soon, I know I'm going to want to control the Blu-ray portion with my standard universal remote. Unfortunately, PS3 uses Bluetooth for its controllers and doesn't support standard IR remotes.

IR2BT to the rescue. It converts IR signals to Bluetooth specifically for this purpose. I can get one of those instead of yet-another-proprietary-remote.

AJAX Progress Indicator Generator

Great site that generates custom AJAX progress indicator graphics. Sample Progress Indicator Select your colors, select the indicator type, and generate it. Free. http://ajaxload.info

Shrine Circus 2008

A clown and a large fez-shaped Shriner mascot parade around the arena.Sunday we went to the Shrine Circus and saw Circus Gatti perform. It was very interesting and brought back some childhood memories as I watched some kids getting an elephant ride. (I didn't think they did that anymore.)

There were some neat acts and I particularly enjoyed the "Extreme Metal Riders," a group of guys who ride motorcycles around in a metal ball. I'd seen three motorcycles at the same time, but these guys do five and six at once.

The thing I thought was most interesting was truly how small the production was. They had several acts, but there were only like 20 people in the circus. You'd see one of the acrobats was also one of the guys riding motorcycles and he was also the juggler. The lady doing an act with a bunch of hula hoops is also the one who does an act on gymnastics rings and was a "cheerleader" for the motorcycle guys.

I had to show some respect for them, out there making their way doing things I know I can't do, but at the same time, having just seen Cirque, it felt so small and... well, cheap. I feel bad saying that, because you could tell these folks were doing the best they could with what they had, and if you throw Cirque sort of money at something, of course it's going to be bigger-better-faster-stronger. Ticket prices reflected that - Shrine Circus ticket: $9; Cirque ticket: $85. You do the math. It was a good time all the same and fun was had by all.

Plus, I had no idea the Shriners had a giant fez mascot. That thing is the bomb.

Laser Hair Removal: Treatment 9

My ninth treatment was Saturday morning. They got a new laser at the facility and I think it's more powerful than the previous one, because it hurt a little more and when I was done I had little red welts all over my face that looked like bad acne. I had this same sort of reaction the very first time I went in for treatment and they tried the laser on me, so it's not like I'd never seen it before and I definitely wasn't worried. That said, it was sort of painful and the technician put some ointment on my face and told me not to shave or otherwise irritate it for a day.

My chin is really the only really dark hair I have left on my face, and that's patchy at best. The rest of my face has small hairless patches among sparse hair patches where the hair is growing, but is much finer and more manageable. My upper lip still has a decent amount of hair on it, but the tech is really jumping in on that to make sure it's taken care of.

I have three more treatments in this "package" (they sell treatments in packs of six). I'm looking forward to where I'm at when I end this set. Wondering if I'll need more or not. I don't know if I'll be totally hairless, but it'll be considerably thinner. I've definitely enjoyed the results so far - I haven't ruined any shirts, sheets, or pillowcases for quite some time now (my beard used to just destroy these things).

Product Ideas for April 2008

Okay, folks, here are your million-dollar product ideas for April 2008. If you implement these, remember to send me a t-shirt or something.

Coffee should come in milk cartons.Coffee should come in milk cartons. I can't really remember the last time I actually measured coffee into the coffee maker. Once you've done it a couple of times, you know that a mound of coffee about this big is the equivalent of two scoops or whatever. But pouring coffee into the machine out of a bag is, well, sometimes troublesome. You kind of have to manually munge a "spout" on the end of the bag, too much comes out... bah. Other containers - cans, tins, etc. - are also problematic. Put it in a milk carton so I can pour it.

Combine Dance Dance Revolution and Rock Band for the ultimate music experience. I think I have like six versions of DDR at home. I know I have at least four dance pads across two different consoles. I love DDR. I also love Rock Band. They should let you hook up more than four people in Rock Band. Keep the four band members - guitar, bass, drums, vocals - but add the ability to hook up dance pads. The vocalist could dance while singing, and additional dance pads could be added for "backup dancers." Hey, if the guitarist really wants to get crazy, dance while playing the guitar. You could combine that with the stage kit coming in June and have yourself a full production, ready to go on tour. I'd totally buy it.

Two Minute WF: WorkflowRuntime

In this Two Minute WF, we'll talk about the WorkflowRuntime.

The WorkflowRuntime is the service that coordinates the execution of workflows and the services that workflows use. Once you've defined a workflow using the various activities you need the workflow to perform, you tell the WorkflowRuntime to create an instance of that workflow and start it running. The WorkflowRuntime uses the various services available to it to start the workflow instance running on a thread, persist the workflow when it becomes idle, and generally manage the execution of the workflow.

The WorkflowRuntime provides events you can handle to let you know when significant things happen like when a WorkflowInstance is finished running, has thrown an exception, or has been terminated. You can also use the WorkflowRuntime to enumerate the list of currently loaded workflows or retrieve references to workflow-related services.

You can only have one WorkflowRuntime per AppDomain (generally this means you get one per application), so in more than the simplest application it can be kind of tricky to manage your WorkflowRuntime.

For example, say you have an object that needs to know when a workflow completes. You might have that object subscribe to the WorkflowRuntime.WorkflowCompleted event. Later, you might no longer need that object so you stop referencing it and assume the garbage collector will clean it up for you... but it won't. Why? Because it's still subscribed to the WorkflowRuntime.WorkflowCompleted event so there's still a reference to it. This sort of thing becomes a little tricky particularly in applications like an ASP.NET web app where a page instance might need to know when a workflow it started is done running. (There are other issues with using workflows in ASP.NET that I'll get into in a later topic.)

There's a lot to consider when working with WorkflowRuntime, but it does a lot of the work for you. Once you get your head wrapped around it, WorkflowRuntime is your best friend in Windows Workflow Foudnation. You'll be seeing a lot of each other, so get to know it.

posted @ Wednesday, April 02, 2008 9:26 AM | Feedback (0) | Filed Under [ .NET ]

Speaking at InnoTech Oregon 2008

The InnoTech Oregon conference is going on April 16 and 17 at the Portland Convention Center. I'll be speaking in the Developer track on "Unit Testing with TypeMock."

Unit testing checks the behavior of the code you write by testing just that code, isolated from the rest of the system. It’s complementary to integration testing and is an important step toward ensuring reliability of the entire system in production. Unfortunately, not everything is designed with testability in mind. Third-party dependencies can throw a wrench in the works. You may need to add tests for legacy code that isn’t easily isolated. And what if the public-facing methods and properties on your code make it easy to use but hard to test? This session will show you how to have your unit testing cake and eat it, too, using NUnit and TypeMock.

I'm the last session of the last day - April 17, 3:30p - so if you want to see some TypeMock Isolator in action, come check it out.