xUnit.net

May 25, 2009

xUnit.net 1.5 CTP 1

This morning, we published the first CTP of xUnit.net 1.5. This release includes a new GUI runner, support for ASP.NET MVC 1.0 RTM (for both C# and VB.NET), and several bug fixes.

A note for Resharper users: support for xUnit.net in Resharper has been moved to the xUnit.net Contrib project, and is no longer part of the core xUnit.net distribution.

New GUI Runner

xUnit.net Test Runner (1.5 CTP 1)

Our goal with the new UI is to streamline the test running process for test-first developers. It is common for test-first development to result in several test assemblies and thousands of tests. The traditional thinking of test runners and tree representations of tests seems to fall apart when your test list becomes large.

We wanted to give developers a quick way to filter test lists that don’t involve navigating large trees. This first CTP allows users to filter by loaded assembly, as well as using a search box which live-filters the lists of tests. Additionally, the user can use the test list to select a subset of tests to run.

What’s Left To Do?

This runner is still in a very early state. We wanted to get it out and get user feedback. We have several features (and some significant code restructuring) left to implement before it will be ready. We are intending to re-add the automatic assembly reloading feature, as well as additional test list filtering (for example, filtering by traits). Mostly, though, we would like to see the community provide feedback on the general effectiveness of the design for their day to day runner needs.

We will be releasing at least one more CTP before we release the final 1.5 bits. Please take this opportunity to try out the new runner and let us know what you think!

February 22, 2009

Announcing xUnit.net Contrib

Jim and I have a relatively limited amount of time to work on xUnit.net, since we’re not together in the same group any more. One of the things that has suffered as a result was the Resharper runner support, particular since neither of us uses Resharper. This has been complicated by the fact that the Jetbrains team seems intent to breaking their extensibility APIs with every single release.

Matt Ellis approached us about contributing some fixes for the Resharper runner, and we all though it might be a great opportunity to launch an xUnit.net Contrib project on CodePlex. Matt has very graciously agreed to run the project, whose first deliverable is a new Resharper runner with several bug fixes.

Thanks, Matt!

Everybody who uses xUnit.net and Resharper should go download the new runner bits. :)

November 27, 2008

xUnit.net 1.1 Released

Yesterday, we published xUnit.net release 1.1.

In addition to new features like TeamCity support, there are also several breaking changes; please review the breaking changes blog post for more information. We also documented the XML format that is used for xUnit.net's native XML output, as well as used for version-resilient test runner authors.

Look for a separate blog post soon on authoring your own test runner for xUnit.net.

October 06, 2008

Breaking Changes in xUnit.net 1.1

Updated November 28 with the release of xUnit.net 1.1.

We've just released xUnit.net version 1.1, and we wanted to take the opportunity to do a little cleanup work (that will have breaking changes).

We've added the following features:

  • Support for TeamCity; requires:
    • TeamCity v3.1 or later
    • Tests linked against xunit.dll v1.1 or later
    • xunit.console.exe or xunit.runner.msbuild.dll v1.1 or later
  • Higher level version-independent runner APIs (more below).

We also made the following breaking changes from v1.0x:

  • Renamed XunitExt namespace to Xunit.Extensions.
  • Renamed DLLs:
    • xunitext.dll => xunit.extensions.dll
    • xunitext.runner.msbuild.dll => xunit.runner.msbuild.dll
    • xunitext.runner.jetbrains.dll => xunit.runner.resharper.dll
    • xunitext.runner.tdnet.dll => xunit.runner.tdnet.dll
  • Dropped the xunitext35.dll project entirely (see more below)
  • Added a <start> XML element to the version independent runners (see more below)

TeamCity Support

The console and MSBuild runners will automatically detect when they're running in the context of TeamCity, so no changes are necessary to your automated build files, and you can use the same build targets for interactive use and continuous integration.

Dropped xunitext35.dll

The unit test extension methods for .NET 3.5 have never been a fully planned or developed feature, and as such, we moved them to the Samples project.

The new <start> XML element

The <start> XML element was added to xunit.dll v1.1 for version independent runners to be notified that a test is beginning to run. This should allow runners to show which test is currently running, which can be helpful when diagnosing issues with long-running tests. Version independent runners which are linked against ExecutorWrapper need to be written in such a way to cope with the presence or absence of the <start> element, since the it will only be provided when the tests are linked against xunit.dll v1.1 or later.

Higher level version-independent test runner APIs

One of the things we've had on our list for a while is documenting the XML that's used to communicate between version independent test runners and the xUnit.net execution engine. Today, you can link against xunit.runner.utility.dll and use the ExecutorWrapper class to gain access to these XML-based APIs, but since the XML was undocumented, it is a rarely used API. We have since documented the XML format on the project wiki.

Second, we introduced a higher level abstraction for version independent runner authors, which "cracks" the XML elements and converts them into calls against a new interface named IRunnerLogger. The version independent runner author implements this new interface, and uses the callbacks to the logger to present information to the user about the progress of the test run, as well as allowing the user to cancel the test run.

In the process of fleshing out these new runner APIs, we've converted all our runners (except ReSharper) to use them. Until I can write a blog post specifically designed to assist test runner authors, the best place to start understanding how runners are written is to look at the source code for our MSBuild runner.

It will still be important to understand which XML elements are supported based on which version of xunit.dll the user linked against. For example, if the user is linked against a version of xunit.dll prior to v1.1, the XML will not contain any of the <start> elements (and therefore IRunnerLogger.TestStart will never be called). Authors of version independent runners will need to be able to deal with the variance present between the available versions of xunit.dll. The XML format documentation shows which version of xunit.dll introduced each element and attribute.

We will continue to support the XML-based APIs as well as these newer APIs.

September 16, 2008

xUnit.net 1.0.3 Released

We shipped xUnit.net 1.0.3 today. Primarily this release is about adding support for ReSharper 4.1, but it also fixes a couple of annoying ReSharper-related bugs.

Enjoy!

xUnit.net 1.0.3 installer

August 25, 2008

xUnit.net 1.0.2 Released

Jim and I finished up work on xUnit 1.0.2 on Saturday and we pushed the publish button this afternoon. The one new notable feature is support for Resharper 4.0. We also fixed five bugs in the bug database (and probably a few more here and there that didn't get tracked).

It's been almost 3 months since 1.0.1, and if it doesn't seem like we've made a lot of progress for those three months, you're probably right.

  • When I was on the CodePlex team, we had a dedicated 20% Slack day to work on xUnit.net, so it got ~ 40 hours/month work on it. Now that I'm on the ASP.NET team, Jim and I have to carve off a Saturday or Sunday, and we're probably running more like 12-18 hours/month right now.
  • It's summer, and the end of the fiscal year at Microsoft, so there has been inevitable vacations, plus speaking gigs for both of us where travel eats into the weekend.
  • We've been working on trying to make progress with our GUI runner, as well as doing some investigative work around supporting the Visual Studio Test runner. While we are making progress of sorts, it's not the kind of "release every month" progress right now.

Hopefully we'll be able to find some more solid time to work on it soon. Now that we have an officially supported release for Resharper 4.0, we can re-focus on the other runners.

August 20, 2008

xUnit.net: Support Visual Studio Test Runner?

Jim and I have been doing some investigation into the idea of supporting the Visual Studio test runner, and we’ve come across some issues that we think requires the input of the community.

If you’re interested in using xUnit.net with Visual Studio’s test runner support (Visual Studio 2008 SP1, Professional Edition or higher), please visit the xUnit.net forum post that describes the situation and provide us with your feedback.

Thanks!

May 30, 2008

Mocking Still Not Quite There For Me

The release of Moq (and the subsequent updating of Rhino Mocks in response) has made mock frameworks much more approachable to me, but I still find situations where hand-rolled stubs seem to work best.

Wednesday, Jim and I were trying to see what it might look like if we replaced our stubs with a mocking framework. We have two interfaces which we are hand stubbing today:

public interface ITestCommand
{
  string Name { get; }
  bool ShouldCreateInstance { get; }

  MethodResult Execute(object testClass);
}

public interface ITestClassCommand
{
  object ObjectUnderTest { get; }
  ITypeInfo TypeUnderTest { get; set; }

  int ChooseNextTest(ICollection<MethodInfo> testsLeftToRun);
  Exception ClassFinish();
  Exception ClassStart();
  IEnumerable<ITestCommand> EnumerateTestCommands(IMethodInfo testMethod);
  IEnumerable<IMethodInfo> EnumerateTestMethods();
  bool IsTestMethod(IMethodInfo testMethod);
}

A quick background on some of the types involved here:

  • ITestClassCommand represents a “class with tests”. It’s used by the execution engine when running the tests. Most of what’s used there isn’t important, but what is important for this test is EnumerateTestCommands().
  • ITestCommand represents a “single execution of a test”. Each test method may yield multiple executions (think data-driven testing), which is why ITestClassCommand.EnumerateTestCommands() returns a collection of these rather than just one.
  • IMethodInfo is an abstraction of the CLR’s MethodInfo class, which is necessary because sometimes when you’re being asked to enumerate these things, you don’t actually have a real MethodInfo (f.e., when ReSharper is asking you to tell it what tests exist in the source file that user is looking at).

The actual class under test is TestCommandFactory. Its single responsibility is: given a ITestClassCommand instance and a MethodInfo, generate the ITestCommand instances to run all the tests. It does more than just get the instances from the class command: it wraps them using the chain of responsibility pattern to provide all the extra work that goes into running and reporting on a test command, which includes:

  • Running all the BeforeAfterAttributes found decorating the test method
  • Creating a new instance of the type under test (if the inner ITestCommand.ShouldCreateInstance is true)
  • Turning Trace.Fail and Debug.Fail statements into thrown exceptions
  • Catching exceptions thrown by the test and turning them into FailResult objects
  • Timing how long it takes to run the class

As you can see, the presence and absence of these things is important, and order is also important. Our hand-rolled stubs record the values that were passed in, and allow you to control values that were returned. Our test, in pseudo-code, is approximately:

Arrange:

Create a stub of ITestCommand (stubTestCmd) - In response to ShouldCreateInstance, return true

Create a stub of ITestClassCommand (stubClassCmd) - In response to EnumerateTestCommands, return StubTestCmd

Get the MethodInfo for an empty, void-returning method (methInfo)

Act:

Call TestCommandFactory.Make, passing stubClassCmd and methInfo

Assert:

Ensure that the IMethodInfo passed into stubClassCmd.EnumerateTestMethod wrapped methInfo

Ensure that we returned a wrapped ITestCommand (test all the levels of wrapping described above)

Because our stubs record the passed-in values and we can inspect them, our first assertion is easy to write:

Assert.Same(methInfo, stubClassCmd.EnumerateTestCommands_TestMethod.MethodInfo);

Note that we’re not just testing the value (that would be stubClassCmd.EnumerateTestCommands_TestMethod) but we’re actually diving into it and testing a specific value (.MethodInfo). This is because ITestClassCommand takes an IMethodInfo, but we actually pass a MethodInfo to the method under test.

When we tried to convert this to Moq, we were stuck. We could make a Mock<ITestClassCommand>, but we could neither specify (via .Expect) nor verify (via .Verify) against the data item it recorded. We actually need the actual value; the wrapper isn’t important, but what it wrapped was.

We found a way to write the test, which was to cascade a .Callback after the .Expect and do the assertion. However, this put assert logic up inside our arrange. Alternately, we could’ve stashed the value into a temporary and did the assertion afterwards, but that made things start to feel a little unwieldy compared to the hand-rolled stubs.

We also found the use of “Expect” to be unfortunate, particularly the syntax that we ended up with (approximately):

var mockClassCommand = new Mock<ITestClassCommand>;
mockClassCommand.Expect(x => x.EnumerateTestCommands(It.IsAny<IMethodInfo>()))
                .Returns(new List<ITestCommand>(mockTestCmd));

Our problem is with the monstrosity of “It.IsAny<IMethodInfo>()”. It looks bad enough with a single parameter, but would look positively awful with several parameters. The truth is that I rarely want to say “if given A, return B”; I almost always say “return B, and I’ll verify in the Assert that I was passed A”. This would be a much better syntax:

var mockClassCommand = new Mock<ITestClassCommand>;
mockClassCommand.Stub(x => x.EnumerateTestCommands)
                .Returns(new List<ITestCommand>(mockTestCmd));

The compiler error I get from this tells me that the Lambda system in C# 3 probably won’t ever let me get to this kind of a syntax. I’m also not even sure about what the syntax would look like that lets me inspect the executions of each call to EnumerateTestCommands, so that I could ensure it was only called once and that the wrapper wrapped the right thing.

I think Wednesday we came to the realization that a code generator was probably what we were going to end up with. I’ve come around several times to the problem and, even after seeing Lambdas in C# 3, concluded that a generator which could creates stubs of any interface/abstract class is still the ideal situation.

May 28, 2008

xUnit.net 1.0.1 Released

We just shipped xUnit.net 1.0.1 today. Aside from a handful of bug fixes, the two major things addressed for this release are:

  • Support for ASP.NET MVC Preview 3 (released yesterday)
  • Support for newer builds of F#

Enjoy!

May 13, 2008

The Past, Present, and Future of .NET Unit Testing

If this feels like a repeat, then you might be living in that cool Star Trek: TNG episode where the ship blows up in the teaser! Or, it might be that the show's actually available now. :)

At the ALT.NET conference in Seattle last month, Scott Hanselman said he wanted to use the opportunity of all these people being physically together to do some unique podcasts. On my way off to party after the end of Saturday's talks, I received a phone call asking me to come back so we can do a "quick" podcast with all the .NET unit testing framework people. (Note to Future Brad: Hanselman's "it'll only take 20 minutes" means an hour, at least :) ).

The result was an interesting discussion about the evolution of unit testing on the .NET platform. I was there to represent xUnit.net; Charlie Poole was there to talk about NUnit; Jeff Brown was there to tell us about MbUnit and the Gallio test runner; and Roy Osherove was there discussing unit testing in general and the book he's writing, "The Art of Unit Testing".