Joe White’s Blog

Life, .NET, and Cats


Archive for March, 2007

NUnitLite: Embedded, readable tests

Sunday, March 25th, 2007

I’m about to write some unit tests for my Lua-based game engine, and decided it was time to take a look at NUnitLite. Mainly because I want to play with its self-descriptive and, above all, forwards assertions:

Assert.That(actual, Is.EqualTo(expected));

// Output:
1) TestFoo (Tyler.Tests.TestTest.TestFoo)
Expected: 5
But was:  4

(I’ve ranted about xUnit’s backwards assertions before, so I won’t bore you with that again. Suffice to say, this is much, much cooler than NUnit.)

So I downloaded it and tried it out, and found that there are some gotchas. Nothing show-stopping yet, but some things that it would’ve been really nice to know about before I started. So I’ll share.

Getting NUnitLite

As of today, NUnitLite has not shipped any releases. So you’ll have to download the latest code from the NUnitLite source repository. You can download any changeset, but you probably want the latest (the topmost row in the grid — changeset 11989 when I downloaded). Click the disk icon in the left column to download a ZIP.

There’s a solution file in NUnitLite\src, but don’t bother opening it. It contains tests for NUnitLite itself, and those tests are NUnit tests — so they won’t even compile unless NUnit is wherever they expect it to be.

What you want is the NUnitLite\src\NUnitLite directory and project. Copy that into the solution directory where you want to start using NUnitLite, and add it to your solution. (NUnitLite is meant to be embedded, so you compile it in your solution just like all your other projects.)

Making NUnitLite return an exit code

Out of the box, NUnitLite doesn’t return a nonzero exit code when tests fail. This makes it completely worthless for any kind of automation. What good are unit tests if they don’t fail the automated build?

Fortunately, this is pretty easy to get around. You can do either of two things: modify the NUnitLite source code, or run the test-runner object yourself. I chose the latter, for now.

See below for some code you can put in your program’s Main() method to run NUnitLite properly, including return of a nonzero exit code when tests fail.

Quick overview of NUnitLite

As with most test frameworks, you define “test fixture” classes and put test methods on them. Setup and teardown are supported.

You can choose to make your test-fixture classes descend from the NUnitLite.Framework.TestCase class. This doesn’t seem to gain you much, though, and TestCase doesn’t have a default constructor, so you’d have to add an explicit constructor to your test fixture. Personally, I don’t bother descending from TestCase.

Test fixtures: Your test fixture must have the [TestFixture] attribute, whether or not it descends from TestCase. There’s no restriction on the class’s visibility, although I always make them public out of habit.

SetUp and TearDown: If you’re descending from TestCase, you can just override the SetUp and TearDown methods. Otherwise, make a method and tag it with the [SetUp] or [TearDown] attribute.

Test methods: Like DUnit, NUnitLite recognizes tests by name. Any public method whose name starts with Test (case-insensitive) is considered to be a test method. No more cluttering your code with all those stupid [Test] attributes! Yay! (Pity they didn’t do the same thing for SetUp and TearDown, but, oh well.)

Assertions: In addition to the uber-cool Assert.That() assertions, NUnitLite also supports the old NUnit-style Assert.AreEqual() assertions.

Setting up an NUnitLite test project

Create a new console application. Replace its Main() method with either of the following blocks of code.

Make sure that you’ve added the NUnitLite project to your solution. Then in your new console application, add a reference to NUnitLite (using the Projects tab of the Add Reference dialog). Also add a reference to the project containing the code you want to test.

Then you need to write the Main() method that starts up your app and runs the tests. I’ll present two different code blocks that both accomplish this; choose the one that suits your needs.

Non-automatable. If you will always rely on visual inspection to see if the tests passed or failed (i.e., you’re always running the tests manually, always looking at the output, and never automating anything), you can use this simple Main() routine:

using NUnitLite.Runner;

namespace <your namespace here>
{
public class Program
{
public static void Main(string[] args)
{
ConsoleUI.Main(args);
}
}
}

Automatable. If you actually care about making your tests automatable, you should use this Main() routine instead. It will return an exit code of 1 if any of the tests fail (or if any other type of exception occurs), so you can easily plug it into any style of automated or continuous build, and it will fail the build when the tests fail. (See below for a way to make it fail the compile right in Visual Studio.)

using System;
using System.Reflection;
using NUnitLite.Framework;
using NUnitLite.Runner;

namespace <your namespace here>
{
public class Program
{
public static int Main()
{
CommandLineOptions options = new CommandLineOptions();
ConsoleUI runner = new ConsoleUI(options, Console.Out);
try
{
TestResult result = runner.Run(Assembly.GetExecutingAssembly());
if (result.IsFailure || result.IsError)
return 1;
else
return 0;
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
return 1;
}
}
}
}

A sample NUnitLite test fixture

using NUnitLite.Framework;

namespace Tyler.Tests
{
[TestFixture]
public class AdderTests
{
private Adder _adder;

[SetUp]
public void SetUp()
{
_adder = new Adder();
}

public void TestZeroes()
{
Assert.That(_adder.Add(0, 0), Is.EqualTo(0));
}
public void TestTwoPlusTwo()
{
Assert.That(_adder.Add(2, 2), Is.EqualTo(4));
}
}
}

Failing the compile when the tests fail

If you want, you can set up your tests to run automatically every time you compile in Visual Studio, and to fail the compile if tests fail. Here’s how:

  • Make sure you used the “Automatable” Main() method (see above).

  • In Solution Explorer, right-click on your project, and go to Properties.

  • Go to the “Build Events” tab. In the “Post-build event command line” box, type the name of your test EXE. In my case, my project is called Tyler.Tests.csproj, so I just type Tyler.Tests for my post-build event.

Save everything and build. Now, every time you build your test project, your test project will automatically run, and if it returns a nonzero exit code, Visual Studio will show “The command ‘Tyler.Tests’ exited with code 1” in the Error List window. Then you can press Ctrl+Alt+O to view the Output window, where you can see the test output, and see which tests failed and with what messages.

Amusing side note: When I first tried hooking this in as a post-build event, I actually put it in as a pre-build event by mistake. And then I just couldn’t figure out why the test kept failing even after I fixed the code…

Walter Reed Hospital: the other side of the story

Thursday, March 22nd, 2007

I know this isn’t relevant to what I normally blog about, but it’s compelling.

You’ve probably already heard all the news coverage about the conditions at the Walter Reed Army Medical Center. But most of the coverage so far has been from the media looking for sensationalism, and from brass hats and politicians covering their asses.

Here, on the other hand, is an account from a senior chaplain at Walter Reed.

The news media and politicians are making it sound like Walter Reed is a terrible place and the staff here has been abusing our brave wounded soldiers; what a bunch of bull!

I was in shock when the news broke. We in the chaplains office in Walter Reed, as well as the majority of people at Walter Reed, did not know anyone was in building 18. […] Building 18 is not on the installation of Walter Reed and was believed to be closed years ago by our department. The fact that some leaders in the medical brigade that is in charge of the outpatients put soldiers in there is terrible.

What I am furious about is that the media is making it sound like all of Walter Reed is like building 18. Nothing could be further from the truth. No system is perfect but the medical staff provides great care in this hospital. What needs to be addressed, and finally will, is the bureaucratic garbage that all soldiers are put through…

I appreciate this guy’s agenda — improving hospital conditions for wounded soldiers — a whole lot more than I appreciate the CYA agenda of the politicos. Go read what he’s got to say.

Lua looks pretty cool…

Thursday, March 15th, 2007

Lua is an open-source scripting language that’s designed to be embedded into larger apps. I know it’s used in World of Warcraft and SciTE. There are examples out there of using Lua from Delphi apps. And through another open-source project, LuaInterface, you can embed Lua scripting into a .NET app, so easily it’s almost silly.

I’m writing a video-game engine in .NET, and I looked into Lua because I want to be able to have sandboxed game packages. The idea is that if someone already has the game engine installed, they could download game packages from the Internet and run them as fully-functional games without fear of viruses or Trojans. So I wanted a scripting environment that could run in a sandbox, with, for example, no access to the filesystem. It turns out this is trivial with LuaInterface:

Lua lua = new Lua();
// Don't let scripts use the "io" or "debug" packages.
lua["io"] = null;
lua["debug"] = null;
// Don't let them call the "dofile" method either.
lua["dofile"] = null;
// etc.

Classes1 and methods are both reference types, and to make them go away, you just need to nil out the global variable that holds the reference. There are only a few dozen of these globals when you spin up Lua, so it’s not hard to go through them and decide which ones are safe for a sandbox and which aren’t.

It’s easy to push values into, and read values out of, the Lua environment:

lua["answer"] = 42;
lua.DoString("print(answer)");
int answer;
answer = (int) lua["answer"];
answer = lua.GetInteger("answer"); // equivalent

You can even assign .NET objects into Lua variables, and all their methods and properties are instantly callable from Lua. Alas, this is not sandbox-friendly in the shipping version of LuaInterface, because by default, Lua can call private methods on that .NET object! But there’s an easy code change to LuaInterface that fixes this.

And Lua has built-in coroutine support. So I can use it for writing cooperative, synchronized scripts for sprite interaction. I’ll definitely be posting more about this.

1 Technically, they’re not classes, they’re “tables”, which are kind of like supercharged associative arrays. There’s some good Lua documentation if you want to know more; I’d recommend starting with Programming in Lua.

ReSharper, day 31: Safe Delete

Sunday, March 4th, 2007

Welcome to day 31 of my 31 Days of ReSharper. (Okay, so it’s a day late. I took yesterday off.)

The last ReSharper refactoring I’m going to cover is Safe Delete. It’s accessible through the Ctrl+Shift+R menu, or directly via Alt+Del.

Safe Delete brings up another of ReSharper’s refactoring wizards. The first page (which, in many cases, is the only page you even see) is pretty boring, since there really aren’t that many different ways to delete something.

The first page of ReSharper's Safe Delete wizard

The general idea of Safe Delete is that it will delete something without breaking your code. It does two things:

  • Checks for problems. If you try to delete a method, and that method is still used somewhere, ReSharper will warn you, and give you a chance to cancel the delete. You can click one of the hyperlinks to jump to the code, or you can show all the problems in the Find Results window.

    ReSharper's Safe Delete wizard, warning of places that still use the member being deleted

  • Carries the changes through. If you delete a parameter, all the call sites will be updated. If you delete a virtual method or an interface method, you get asked if you want to delete it from all the descendant classes as well.

    ReSharper's Safe Delete wizard, asking if you want to delete descendant members as well

Safe Delete is fabulous in theory: if we suspect code is unused, we can confirm that it’s not used and delete it and update all the call sites in a single operation. It even gives us a way to manually check for unused parameters, since ReSharper doesn’t bother checking for unused parameters in public methods. You wouldn’t want to manually run Safe Delete on every parameter of every method in your solution, but when you suspect something’s amiss, it’s a good cleanup tool.

But as I found while I was researching this post, its checks are far from perfect. It seems to do pretty well at carrying the changes through, but it’s got a ways to go on checking for problems first. So:

A word of caution

Always compile just before, and again just after, you use Safe Delete. Because it can break your code.

Here are a couple of cases I found in just a minute or two of poking around:

  • If a method is used as a delegate, and you Safe Delete a parameter, ReSharper will let you. After that, obviously it doesn’t match the same delegate type anymore, so the code won’t compile. (They will warn you if you try to delete the entire method, though, so they’re at least partly delegate-aware.)

  • If you’re overriding a method from another assembly (e.g., you’re overriding System.Windows.Forms.Control.IsInputKey), and you Safe Delete a parameter from your method, ReSharper will delete the parameter without warning you about the ancestor. So the override won’t compile anymore, since there’s nothing with a matching signature for it to override.

I don’t mean to suggest that it’s always going to break your code. Far from it, especially if you’re paying attention. (I knew better than to try deleting a parameter of an event-handling method, I just wanted to see what it would do.) Its checks will catch you in most cases. But it’s still a good idea to compile before and after.

ReSharper, day 30: Rename, including Viral Rename

Friday, March 2nd, 2007

Welcome to day 30 of my 31 Days of ReSharper.

Today I’m going to talk about that mother of all refactorings, Rename, available via F2. It is, of course, also available through the Ctrl+Shift+R menu.

Now, there’s only so much you can say about a Rename refactoring. Generally, either it works or it doesn’t; there’s a limit to how cool it can be. But ReSharper does manage to pull off a few nice tricks.

Note: Due to a combination of technical difficulties, a lack of planning, and a couple of big snowstorms, I’m currently unable to use ReSharper at home. So today’s post (and perhaps tomorrow’s too) will not have screenshots, and the details will be from memory. Please correct me if I get anything wrong. I’ll try to come back later and clean these up.

Renaming local variables: SyncEdit and suggestions

When you rename a local variable, ReSharper uses SyncEdit (my name for it, not theirs) to let you make the change right there in the editor. It also pops up its list of suggested variable names, so you can select a name from the list.

I’m used to Delphi, where I have to press Esc to end SyncEdit mode and apply my changes. Turns out this is poor preparation for ReSharper, because when you hit Esc in ReSharper’s SyncEdit, it reverts your changes. In ReSharper, you have to hit Enter to apply the change. (Yes, it would’ve made more sense if Delphi did it that way too.)

Now, using Enter to save your changes does make sense, but it has a downside: if the variable-name list is showing, Enter will select the current item in that list. So if you want to name your exception object, say, ex, and you type ex, pressing Enter will not rename your variable to ex — it will rename it to exception, because that’s the first variable-name suggestion that starts with ex.

Here’s the workaround for entering shorter variable names: if you press Esc once, it will dismiss the variable-name suggestions, but will not end SyncEdit. (You need to press Esc again, with the suggestion list already gone, before it will revert your rename.) So you need to press Esc to get rid of the suggestions, and then Enter to apply the rename.

Renaming classes: Viral rename

I have long wished for a viral rename refactoring — one that infects all the code around it. For example, if I had a class called SongFile, chances are I would have a lot of variables called songFile or file, a lot of properties called SongFile, etc. I want a rename that, when I rename SongFile to SongDataStore, infects all those variable names and property names, and renames them too.

ReSharper has it.

Well, mostly, anyway. When you rename a class, you get a wizard, and the first page asks you for the new name; nothing too exciting there. But then it looks for variables and properties that (1) match the type you’re renaming, and (2) have names similar to part of the name that you’re changing. And it will show a second page listing them, and suggesting new names for them all. You can uncheck any that you don’t want to rename, but why would you want to do that?

The only downside is that it doesn’t do the same for descendant classes. But I’ve filed a feature request, so we’ll see…

ReSharper, day 29: Refactoring with interfaces

Thursday, March 1st, 2007

Welcome to day 29 of my 31 Days of ReSharper.

Working with interfaces is, traditionally, pretty frustrating. You need them when you’re writing testable code, so you can fake the filesystem and pass in null objects, but they’re a pain when you’re trying to follow what the code is actually doing.

ReSharper has several features that make it much easier to work with interfaces. I’ve already covered two, Navigate to Inheritor and the Type Hierarchy view.

Today I’ll cover another ReSharper feature that’s handy when you’re working with interfaces: the “base method” prompt.

ReSharper prompt: Method 'Engine.RoomScreen.Update(int)' implements method from interface 'IScreen'. Do you want to rename the base method?

If you apply a refactoring — for example, a rename — to a method, and that method is there to satisfy an interface, ReSharper will ask if you want to apply that refactoring to the interface instead.

This dialog box kind of klunky — it disrupts the flow of my thinking, and it’s not the easiest question to understand. It just doesn’t work the way I think. Unfortunately, I don’t have any suggestions for improving it.

That said, I do love this feature. If I decide to rename a method, ReSharper will automatically jump in there and ask if I want to rename it on the interface as well. Usually the answer is yes, because that’ll keep the code compilable. (Sometimes the “yes” is preceded by “Oh yeah, that method is from an interface, isn’t it?”).

This also applies to Find Usages. If you try to Find Usages on a method that implements an interface, you’ll get asked “did you mean the method here, or the same method when accessed via the interface?” In this case, you may have to do the search twice to really get all the usages of that method (although if you’re diligent about only using the class through the interface, then you could just answer Yes and only do the search once.)


Joe White's Blog copyright © 2004-2011. Portions of the site layout use Yahoo! YUI Reset, Fonts, and Grids.
Proudly powered by WordPress. Entries (RSS) and Comments (RSS). Privacy policy