testing, aspnet, gists, csharp, net comments edit

Let’s say you’re writing a service like an HttpModule that performs an action against each page that gets served up.  Maybe it does something like move the viewstate to the bottom of the page, update a property on the page, or fudge the control hierarchy a bit.

The thing is, you want to unit test it, but how?  Mocking an HttpContext is hard enough, and many times you end up going down the UI automation road.  Ugly.

Enter TypeMock.

A few lines of code, setting up the minimum amount of stuff, and you can mock just enough context to actually get a full page request lifecycle to execute - events and all.  So say your service needs to be called during the page PreInit and you can check the results of whatever you did during Load… here’s what that looks like:

[Test(Description = "Tests an external influence on the page lifecycle.")]
public void MyPageServiceTest()
{
  Page page = new Page();

  MockObject<HttpBrowserCapabilities> mockBrowser = MockManager.MockObject<HttpBrowserCapabilities>(Constructor.NotMocked);
  mockBrowser.ExpectGetAlways("PreferredRenderingMime", "text/html");
  mockBrowser.ExpectGetAlways("PreferredResponseEncoding", "UTF-8");
  mockBrowser.ExpectGetAlways("PreferredRequestEncoding", "UTF-8");
  mockBrowser.ExpectGetAlways("SupportsMaintainScrollPositionOnPostback", false);

  MockObject<HttpRequest> mockRequest = MockManager.MockObject<HttpRequest>(Constructor.Mocked);
  mockRequest.ExpectGetAlways("FilePath", "/default.aspx");
  mockRequest.ExpectGetAlways("HttpMethod", "GET");
  mockRequest.ExpectGetAlways("Browser", mockBrowser.Object);

  MockObject<HttpResponse> mockResponse = MockManager.MockObject<HttpResponse>(Constructor.Mocked);

  HttpContext mockContext = new HttpContext(mockRequest.Object, mockResponse.Object);

  using (StringWriter stringWriter = new StringWriter())
  using (HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter))
  {
    mockBrowser.AlwaysReturn("CreateHtmlTextWriter", htmlWriter);
    page.PreInit +=
      delegate(object sender, EventArgs e)
      {
        // Perform some action
      };
    page.Load +=
      delegate(object sender, EventArgs e)
      {
        // Check/Assert the results of your action
      };
    page.ProcessRequest(mockContext);
  }
}

Obviously the majority of this could be wrapped up into a library or something, but I show it here to illustrate that, at least in ASP.NET 2.0, this is all it takes.

(You’ll notice that I’m using the Reflective mocks instead of the Natural mocks that I prefer in TypeMock.  The reason is that I’m mocking a couple of internal things and mocking non-public items requires the Reflective mocks.  By mocking these internal convenience methods, I can greatly reduce the amount of setup for this to run.)

aspnet, net comments edit

I was doing some experimentation with custom web server controls in ASP.NET 2.0 so I created a quick Web Application Project and started throwing some controls in, using them on the page that gets put in the app by default.  Unfortunately, I started getting the following warning:

Generation of designer file failed: Unknown server tag ‘cc1:MyServerControlName’.

For a minute, I thought maybe I had forgotten the <%@ Register %> directive at the top of the page, but, no, there it was:

<%@ Register Assembly="MyTestAssembly" Namespace="MyTestNamespace" TagPrefix="cc1" %>

I struggled for this with some time, building and rebuilding, searching and not really finding much on the web at large, and then I tried something that worked:

If the page and the custom control are in the same assembly, remove the “Assembly” portion of the directive.  For some reason, the designer just doesn’t understand it if you specify the assembly you’re tasked to build.  I’m not sure why.  So the directive becomes:

<%@ Register Namespace="MyTestNamespace" TagPrefix="cc1" %>

Once I did that, everything worked great.  YMMV.

UPDATE: If you’re using master pages and the control in question is inside a Content control, you may still see weirdness about unrecognized server tags.  In that case, add the tag prefix registration to web.config, again omitting the assembly:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <pages>
      <controls>
        <add tagPrefix="cc1" namespace="MyTestNamespace"/>
      </controls>
    </pages>
  </system.web>
</configuration>

One thing I noticed was that this seems to be… maybe a little flakey.  Depending on the circumstances, you may get a page that says your control tag is unrecognized at runtime.  That will require you add the “assembly” bit to the tag prefix registration in web.config… but that will cause you to have trouble in design time because the designer file won’t be generated properly.  Erg.

We went to the Washington County Fair on Saturday and had a blast.  There’s something about going to the fair that’s just generally fun.  This time, they had this great show called “The Pirate’s Parrot Show” going on when we got there.

The Pirate’s Parrot show is this great show where this guy brings out something like 15 parrots of different varieties and, dressed as a pirate (of course), shows you different tricks with the parrots and educates you about them.  None of the parrots are caged - they all just wander around however they want to - and the highlight of the show is him letting them fly freely around the area, passing very close overhead.  It’s definitely not something you see every day.  The whole audience was sort of baffled about why the birds wouldn’t just make a break for it, but he explained that with an analogy: “Why do your kids come back when they wander off?”  At the end of the show, he lets you hold and pet the parrots and answers any questions you might have about them.  All in all, a fantastic show.

Of course, we also had to partake in the fair food - BBQ pork sandwiches, fresh lemonade, and funnel cake.  It really doesn’t get much better than that, though I’m glad we walked all over the place so at least I could say I worked off two or three bites of that funnel cake.  I’m sure my arteries are still irritated with me.

A heck of a lot of fun, and, as Tom Peterson says, “Free is a very good price!”

media, music, auto comments edit

For my birthday, my lovely wife Jenn saved up and got me a new car stereo - an Alpine iDA-X001.  I’ve been wanting a stereo that has direct iPod integration for quite some time now so she took me to Car Toys and we picked this one out.

iDA-X001

It’s more of a controller than anything else, relying on external peripherals to supply the music source.  It’s got a USB connection that you can use to connect pretty much anything to (they have adapters) - iPod, USB memory stick, Zune.  It’s also got an iPod-specific connector that you have to use with older generation iPods (that’s what I have to use).  It doesn’t have a CD player on it, but that’s okay because I don’t really listen to CDs anymore - basically they’re only around long enough for me to put them on the iPod, then they get archived.

What I like is that you control it just like your iPod - you can browse your playlists, listen to your podcasts, the whole bit.  Love it.  The thing that sold me, though, is that this unit has this “MX” feature (“Media eXpander”) that takes the music and “rebuilds” it, making compressed sources (like MP3s and such) sound much closer to the original source.  It’s definitely noticeable, and it’s one of the features I was specifically looking for.  It’s very similar to the functionality of the DFX Audio Enhancer plugin for Windows Media Player.

It also has the ability to plug into a bajillion external devices and control them - Bluetooth, XM Radio, HD Radio… it seems like it can control just about anything.  Only downside is that each of the boxes that you have to get to enable these features run around the $200 - $250 range.  So, like, if I want to control my phone through Bluetooth, I have to buy a $220 box.  If I want to listen to HD Radio, that’s another $250.  You get the idea.  They really get you coming and going on that stuff, but I can’t really complain - the modularity of the thing makes it such that you only really have to buy the bits you want and ignore the stuff you don’t.  I’d consider getting the Bluetooth box, for example, but probably will pass on the XM Radio.

While I was there, I also got an amplifier and a 10” subwoofer with a custom box for the trunk.  I had the stock Bose stereo that came with my car, and it was decent and all, but the bass… sounded great when you were sitting still but disappeared as soon as you’d start driving down the road.  The new amp/sub combo has me back in action.  Thanks, Jenn!