XUnit.NET aims to be the Next NUnit, but it's too soon

Update 1: Brad answers some of my concerns on his blog. Too bad you can't write comments on his posts...

Another update: There's a syntax comparison matrix between NUnit, XUnit and MbUnit.

James Newkirk, one of the original creators of NUnit, which is currently the most popular Unit Testing framework for .NET (he now works for Microsoft at the patterns and practices team if I'm not mistaken) has announced on his blog that together with Brad Wilson (also a Microsoftie) a new Unit Testing framework which is open source (it is hosted on the Microsoft CodePlex site under the Microsoft Permissive License. the new Unit Testing framework's name is XUnit.NET.

James lists some of the reasons for creating this framework as his feeling (and Brad's) that is' time to re-codify some of the rules that had become more apparent in the past year or so about Unit testing and TDD DOs and Donts that they feel are important.

some of the main differentiating properties James lists are:

  • Single Object Instance per Test Method
  • No [SetUp] or [TearDown].
  • No [ExpectedException].
  • Reducing the Number of Custom Attributes.
  • Use of Generics and Anonymous Delegates.
  • Assert extensibility.
  • Test method extensibility.
  • Test class extensibility.

I took a rather quick glance and a shot at using the new framework, and wrote some points down so you get a deeper sense of what's changed if you're familiar with NUnit:

some things James did not mention you should know or I'd like to expand on:

Update 2: The lack of setup and teardown methods is not that bad because you can still get the same behavior: just use the class constructor and implement IDisposable and use the Dispose method as your "TearDown" method. This is more of a design thing than a "Removed feature" although it will still break many tests you have that have this attribute.  There is also a [RunWithNUnit] attribute which I'm not sure how it is used yet.

 

  • There is no Assert.Fail (overlooked? I find this very usable in some instances)
  • Data Driven Testing using the TheoryAttribute and DataViaXX attributes - this is a really cool feature whis feels like the MbUnit's [RowTest] with extensibility to declare where the rows will come from. It already has "providers" for SQL, OleDB and more. I was able to put together a text file based Data Driven test in less than 5 minutes without any documentatoin. the framework API is very usable especially if you look at the source code. see example of how I did this at the bottom of this post
  • It's easy to add a special test attribute that does something before or after the test by by inheriting from a special BeforeAfterTestAttribute
  • There is currently only a console runner
  • But there is already shipping TestDriven.NET support as part of the download! just run xunit.tdnet.installer.exe  that is next to the xunit.framework.dll
  • Assert.Equals is deprecated and ou are instructed to use a generic version of Assert.Equal (without the 's') / I think this is a problem because generics make the Assert code longer to write and read while giving little contribution to the developer of the tests. You could "omit" the initial generic type declaration from the Assert.Equal (so Assert.Equal<string>("a","b") works like Assert.Equal("a","b")) but if you miss on the type of the parameter you get a less than understandable compilation error in the form of "argument type string not assignable to parameter type T"
  • There is no built in Mocking framework (NUnit had Nunit.Mocks though most people didn't even know it existed until they've read this)
  • Assert.Equal on two strings, if it fails, does not add that nice little touch of visual that Nunit has that shwos you with an ascii arrow "----^" where the strings differ first (it tells you the char index but that's less understandable)
  • instead of TestFixtureSetup and TestFixtureTearDown, you need to implement an ITestFixture interface with an "BeforeAllTests" and "AfterAllTests" methods.
  • There is no Setup and teardown. I'm not sure that's such a cool idea even though James thinks it is. Like it our not it does give a nice place to store and reuse code. yes, you can abuse it, but does that mean C# shouldn't support anonymous delegates because people could abuse it?) .  At least give us a Setupand Teardown as part of ITestFixture!
  • Extensibility and creating custom test attributes is pretty easy and straightforward and I like the thinking around the API. it's usable. There is still no solution for what happens if multiple custom test attributes need to be run in a specific order.
  • No Expected exception attribute. use try-catch or Assert.Throws, I find that less readable. James' explanation of why isn't convincing to me. I never came across a case where that attribute failed on the WRONG exception (especially if you set the expected message attribute on it)
  • If you take a look at the tests for XUnit and XUnit.Extensions (part of the src download) you'll see that the naming conventions the use is lacking to my taste. Example: a test called "TheoryWithoutData" - it fills two out of my three required parts of a name: what are you testing, and under what scenario are you testing it under?, but the third one - What is the expected behavior under that scenario? that is missing so you have to read the test code to find out, and that sucks.
  • From looking at the source code, it should be able to also run NUnit tests (backwards compatible)

 

Can XUnit.NET be the Next NUnit?

XUnit has some big things going for it: it is built by the original creator of NUnit who has a LOT of influence in the .NET world. Personally I really get the feeling that I should start using this framework now simply because of who built it. but that is a mistake, and I explain shortly.  the other big things which it has:

  • A nice and simple API and extensibility model
  • The idea of data driven tests
  • hmm.. that's more or less the big stuff. now that I think about it.

It COULD be. but it's not there. simply because the user base is non existent. and what about the developers? are there only 2? how much time do they have on their hands?

Why not contribute to an existing framework?

I don't know why they had gone and built their own. perhaps it's an Ego thing. perhaps they couldn't come to grips with Charlie Poole (the current chief maintainer of Nunit) about what features go in and especially removing some of the existing features. maybe its a microsoft thing where you can't contribute to an outside open source project. perhaps James or Brad can shed some light on this.

Should you start using XUnit?

The short answer is no.

If you have an existing project with NUnit or MbUnit tests, I wouldn't recommend it until there is either feature parity or until you decide you can live without some of the features that don't exist in XUnit (Setup and teardown, test fixture setup and teardown, assembly related attributes and more. Also not that some people tend to have the tests rely on the fact that the same class fixture instance is used to run all the tests in that class so they *share* data between tests in the class (that's a mistake, but if you rely on this you'd be in a world of trouble to move). Don't move an existing project because it will take a lot of effort!

If you have a new project you should not consider using it. it's still risky since it's a new project and may not be too stable yet. the larger the user base, the more stable it is.  unless it's a proof of concept kind of thing, or if you're just testing the waters , it may be OK. right now, I think it's premature.

 

Example: Data Driven tests with the Theory attribute

//The test that reads lines from a text file
 [Theory]
        [DataViaTextFile("..\\..\\logicdata.txt")]
        public void SimpleTest(string s)
        {
            Console.WriteLine(s);
        }

//My custom data reader attribute:
 class DataViaTextFileAttribute:DataAttribute
    {
        private string file;

        public string FileName
        {
            get { return file; }
            set { file = value; }
        }

        public DataViaTextFileAttribute(string file)
        {
            this.file = file;
        }

        public override DataTable GetDataTable(Type typeUnderTest)
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("text", typeof (string));
            string[] lines = File.ReadAllLines(file);
            foreach (string line in lines)
            {
                dt.Rows.Add(line);
            }
            return dt;
        }
    }
Published Friday, September 21, 2007 7:48 PM by RoyOsherove

Comments

Friday, September 21, 2007 11:39 PM by Scott Bellware [MVP]

# SetUp and Teardown Methods in Test Classes

Jim Newkirk is blogging about the down side of setup and teardown methods in test classes, and why you

Saturday, September 22, 2007 12:17 AM by Fear and Loathing

# The World Doesn't Need Yet Another .NET Testing Framework

I have a lot of respect for Jim Newkirk but I was reading Roy Osheroves blog entry about the new XUnit

Saturday, September 22, 2007 2:03 AM by Brad Wilson

# re: XUnit.NET aims to be the Next NUnit, but it's too soon

Hey Roy, thanks for the comments. :) A common theme we were shooting for is simplicity. Here are some answers to your questions:

We did not forget Fail. We attempted to simplify a lot of things in the system. I personally believe that the need to use Fail() means there is probably a missing Assert, so rather than encouraging people to use Fail, I'd like to know what assert is actually missing.

I believe mocking frameworks are best left outside the unit testing framework. Everybody has their feelings on which they like best. Personally I usually hand-write stubs, but of all the ones I've used, I like Rhino best.

"Equals" is a static method on Object. We explicitly override it and mark it obsolete because its name is so close to "Equal", but it's not the same thing.

Generics can be implicitly instantiated. Assert.Equal("foo", "bar") works just fine, since the compiler knows that both are strings and automatically calls Assert.Equal<string> on your behalf.

For a while, we did have BeforeEachTest() and AfterEachTest() as part of ITestFixture, but we felt that leveraging the language as much as possible made more sense. Since we create a new instance of the test object for each test run, you can use the constructor and IDisposable.Dispose() in place of SetUp and TearDown.

We're going to devote a separate article soon to the process of migrating from NUnit, including the usage of our [RunWithNUnit] sample attribute in xunit.extensions.dll.

Thanks again!

Saturday, September 22, 2007 2:34 AM by Brad Wilson - The .NET Guy

# Answering xUnit.net Questions

Saturday, September 22, 2007 11:11 AM by Andrew Stopford's Weblog

# xUnit.net, one more to the mix.

I was away on vacation this week and when ever I go away the week is eventful, I came back to the news

Saturday, September 22, 2007 12:10 PM by ISerializable - Roy Osherove's Blog

# MbUnit vs. NUnit Vs. Team System Unit Testing - Choosing a unit test framework

Update : There's a new Unit test framework called XUnit.NET. More info here. MbUnit is gaining some momentum

Tuesday, September 25, 2007 9:04 PM by Scott Hanselman's Computer Zen

# The Weekly Source Code 6

Tuesday, September 25, 2007 9:31 PM by Scott Hanselman's Computer Zen

# The Weekly Source Code 6

Friday, September 28, 2007 8:18 AM by Adam Goucher » Blog Archive » Introducing xUnit.NET

# Adam Goucher &raquo; Blog Archive &raquo; Introducing xUnit.NET

Pingback from  Adam Goucher  &raquo; Blog Archive   &raquo; Introducing xUnit.NET

Friday, September 28, 2007 12:12 PM by Greg Finzer

# re: XUnit.NET aims to be the Next NUnit, but it's too soon

I've created an NUnit Test Generator.  Would it be worthwhile to make an xUnit or MbUnit Test Generator?  See the current test generator below.

www.kellermansoftware.com/p-30-nunit-test-generator.aspx

Monday, October 01, 2007 5:44 AM by Paul Kohler

# re: XUnit.NET aims to be the Next NUnit, but it's too soon

Why not just add to NUnit? One of the main things I miss from NUnit compared to MBUnit for example is the RowTest attribute... but I would rather make a slight compromise in my test style and call methods from within my test than embark on a new framework!

I did put some effort into a "one line unit test" type framework last year but in practice then I was just using 2 frameworks. Unless theres a huge need I think it better to stick to the mainstream... my 2 cents ;-)

Wednesday, October 03, 2007 1:16 AM by Richard W

# re: XUnit.NET aims to be the Next NUnit, but it's too soon

I love the reduced syntax for xUnit.net. I definately feel that NUnit suffers from bloating tests with more syntax than is required. For example, I often do not require setting up or tearing down tests. If I do why do I need an attribute to do it, when the test framework can just use the constructor instead. Often I do not require most of the feature set that NUnit offers. NUnit is unnessasarily harder to learn than xUnit.net. Often I only want a simple test method. xUnit is a better testing framework to support.

Monday, October 08, 2007 4:10 PM by ASPInsiders

# The Weekly Source Code 6

In my new ongoing quest to read source code to be a better developer , I now present the sixth in an

Monday, October 08, 2007 4:11 PM by Scott Hanselman's Computer Zen - The Weekly Source Code 6

# Scott Hanselman's Computer Zen - The Weekly Source Code 6

Pingback from  Scott Hanselman's Computer Zen - The Weekly Source Code 6

Monday, October 08, 2007 6:29 PM by Chandra

# re: XUnit.NET aims to be the Next NUnit, but it's too soon

I think from a user point of view, use the one suits best in the situation you are testing.

I would still wait for xUnit.NET to mature because when I need some help, I can find a lot of information about nUnit then on xUnit.