Homepage | About Me | Testing ASP.net Book | Best Blog Posts | Personal Projects | Follow me on Twitter | GitHub | SlideShare | RSS
Blog.BenHall.me.uk

Creating your own XUnit Extension

Thursday, January 31, 2008

So far, I have discussed XUnit and the XUnit Extensions but in this post I wanted to discuss how to create your own extensions.  Building your own custom extensions is a very useful as it can make your tests much more readable and maintainable. Especially if you have a lot of tasks which need to be performed before or after your tests are executed.

XUnit provides five main base classes which you can build your extensions upon. 

FactAttribute

The Fact attribute is the main attribute used in XUnit to identify a method to execute and return the result of.  By creating a subclass of FactAttribute we can modify how the test runner should treat the method and allow for customisation. For example, the Theory attribute, which allows for data driven tests, is based on this attribute. The theory attribute customizes how the framework should execute the tests as it creates a separate test to execute based on each DataAttribute added to the test method - this is how TD.net can identify separate passing/failing tests.

If you want to create your own subclass of FactAttribute then the most common scenario will be to subclass from the FactAttribute class, and then override the EnumerateTestCommands method.  This is used to enumerate over the test commands system the test object and it returns an instance of ITestCommand per execution of a test method. By overriding this method, you take control of the test methods to be executed.

ITestCommand is the interface of test execution to be returned, which will be executed by the runner.  The interface has three items, a name property for the name of the test, a parameters property for all the properties of the test and a Execute method which accepts a testClass object.  The Execute method is called in order for the method to be executed. If you just want the standard test execution, then the base concrete class is TestCommand.

Let's have a look at a real example.  Within the Samples project (downloadable from codeplex site) there is a RepeatAttribute class.  The attribute on a method would look like this:

[RepeatTest(5)]
public void RepeatingTestMethod()

The implementation of the attribute overrides the EnumerableTestCommands method, and for the repeatCount (set in constructor) it returns a new TestCommand object to be executed.

protected override IEnumerable<ITestCommand> EnumerateTestCommands(MethodInfo method)
{
    for (int index = 0; index < repeatCount; index++)
        yield return new TestCommand(method);
}

In summary, EnumerateTestCommands defines what tests to execute. ITestCommand allows you to define what happens then they are executed.

BeforeAfterTestAttribute

The BeforeAfterTestAttribute is a very interesting attribute which allows for a lot of interesting attributes.  This attribute allows us to hook into the execution of the tests before and after they have been executed.  Its very simply to implement aswell, BeforeAfterTestAttribute is an abstract class with two virtual methods - before and after.  Implement either or both in your attribute, add it to your test/fact and it will be executed.

Again, in the samples solution there is an example of how to use this. It includes a TracingSplicerAttribute which outputs the name.  The test looks like this:

[Fact, TracingSplicer]
public void TestThis()
{
    Console.WriteLine("I'm inside the test!");
}

The attribute code is this:

public class TracingSplicerAttribute : BeforeAfterTestAttribute
{
    public override void Before(MethodInfo methodUnderTest)
    {
        Console.WriteLine("Before : {0}.{1}", methodUnderTest.DeclaringType.FullName, methodUnderTest.Name);
    }

    public override void After(MethodInfo methodUnderTest)
    {
        Console.WriteLine("After : {0}.{1}", methodUnderTest.DeclaringType.FullName, methodUnderTest.Name);
    }
}

When executing the test, the output is:

Before : Example.TestThis
I'm inside the test!
After : Example.TestThis

This method allows for implementation of Rollback and RestoreDatabase (MbUnit) as they are required to be executed before and after the test but don't interact with the actual execution.

DataAttribute

The DataAttribute allows us to set data providers for use with the Theory attribute. DataAttribute is an abstract class which has a single method, IEnumerable <object []> GetData(MethodInfo methodUnderTest);.  This means that any data you want to use within your tests has to be returned as an object[] containing your different test values. The best implementation of this to look at is the OleDbDataAttribute.

public override IEnumerable< object[] > GetData(MethodInfo methodUnderTest)
{
    DataTable table = new DataTable();

    using (OleDbDataAdapter adapter = new OleDbDataAdapter(selectStatement, connectionString))
        adapter.Fill(table);

    foreach (DataRow row in table.Rows)
        yield return row.ItemArray;
}

This executes the database query and pulls everything into a DataTable in memory.  It then uses the ItemArray method which returns a object[] containing all the columns.  This together with the yield statement means every row is a separate test data set.  Remember the TheoryAttribute then takes each object[] returned and creates a TestCommand object which is a separate test execution.  The end result is a test execution object for each data item which the runner can then execute independently.

If you have a special testing scenario which requires data from a certain source then using this attribute could make your tests more streamlined and a lot easier to maintain without much effort in implementing the attribute.

TraitAttribute

This attribute allows us to decorate the test method with name/value pairs.  Within the EnumerateTestCommands method, you can access these attributes on the MethodInfo by using the GetCustomAttributes() method.  The samples provide us with a CategoryTraitAttribute

[Fact, Category("Slow Test")]
public void LongTest()

With the implementation just looking like this, where it hard codes the key "Category" as we know what the key will be. 

public class CategoryAttribute : TraitAttribute
{
    public CategoryAttribute(string category)
        : base("Category", category) {}
}

We can then use GetCustomAttributes to get type of CategoryAttribute attributes.

RunWithAttribute

This attribute enables you to specify a different framework to execute the tests against, this is the base attribute for the RunWithNUnitAttribute.  If you are interested in this I recommend you download the xunitext source code (available from CodePlex) and look how the NUnit Attribute was implemented.

However, if you are really interested in creating an custom extension, I really recommend you download the source code to XUnit and XUnit Extensions to see how the existing attributes have been created.

Technorati Tags: , ,

Labels: , ,

Alt.Net.UK Conference - More Information

Wednesday, January 30, 2008

The conference is almost upon us and we just wanted to post some more information about what's going to happen.

Friday

1) Topic / Agenda Discussion on Friday 1st Feb between 18:00-19:30 @ Conchango, 36 Southwark Bridge Road, London, SE1 9EU
2) Drinks at Bankside Restaurant & Bar on Friday 1st Feb 19:30-23:00 @ 32 Southwark Bridge Rd, London, SE1 9EU

Saturday
3) Alt.Net.UK Conference Saturday 2nd Feb 09:30-17:30 @ Conchango, 36 Southwark Bridge Road, London, SE1 9EU

The plan is to host an open discussion on the topics / agenda for Saturday at the Conchango offices prior to drinks (don't worry, it's a short walk to the bar).  The aim is to discuss all of the topics which
people want to discuss and talk about.  Afterwards, we will go over to the bar and have a few drinks and some food.  This will be a great opporunity to meet each other and network before the Saturday section.

On the Friday, please aim to be at the Conchango offices for 6.00pm, we would like as many attendees as possible to participate in the Friday discussion because there will only be about 30 minutes for any
rework of the options on Saturday. If you can't make it for 6.00, feel free to still come along at any point during the evening - even if its only to the bar or just the discussion....

On Saturday, doors open at the Conchango offices at 9.00.  At 9.30, we will have a vote of the attendees to determine what topics & speakers are accepted.  At this point, we can get the conversation started and start the sessions. Food\Drink will be provided throughout the day on
the Saturday.  The plan is to finish around 5.30 on the Saturday.

One of the main questions we have been asked is - How will the session submission and voting work? Essentially an open space conference, which this is based on, has two parts
- People propose sessions
- People sign up for sessions
People who propose sessions are responsible for coordinating them.
The type of session can vary. It might be a passive learning presentation (a la Scott Gu on MVC) but it might also be a birds-of-a-feather style discussion. The style is open to the proposer of the session, and might change during the session if the participants bring with them the tools or material to switch. Open Spaces is best when it is interactive not passive.
It would be ideal if everyone could bring something they want to talk about. That does not mean preparing, but just a question. An example session might be this:

Session: Is BDD just a range of practices for TDD.
In this session we ask is BDD a new paradigm or a set of TDD practices. Why do practitioners feel it improves on TDD and what do its detractors feel its dangers are. Where is my road to damascus moment for BDD. I don't practice BDD, so I would love to have a BDD practitioners attend to tell me what I am missing. If there are no BDD practitioners why don't a few of us give it a try and see what we can learn.

Now, as proposer I may come prepared for the second eventuality and have done enough BDD reading that I could help us try it out.  If you wanted to attend this session, you would simply put your name against it on the board and attend at it's allotted time.
Bring your laptops if you have them, you may want to write code. We'll have wireless on the day, and there will be a wiki available to write up and notes/information about the session for everyones benefit. We also have setup newsriver (http://newsriver.altnetuk.com/). Anything tagged with AltNetUK should appear on this page. I'll put up more information about this on the
site.

Finally, thank you to all of you who have registered and our Sponsors - Conchango, Red Gate and Code Better.  We are really looking forward to seeing you next weekend.  We do have one request, if you can no longer attend then please send us a quick email to let us know, just so we can plan numbers and open the space up to someone else.


Regards
Alt.Net.Uk organisers

Technorati Tags: ,,

Labels: ,

NxtGenUG Coventry: Red, Green, Refactor!

Friday, January 25, 2008

Just an early heads up, I will be doing a Test Driven Development talk at NxtGenUG Coventry on Monday May 19th.

My plan for the talk is to start with nothing, and build up a application using a test driven development approach.  Unlikely it will be a feature complete SubText level application, but my aim is to demonstrate how to get started with TDD with some real application features, how to take advantage of mocking and of course some of the excellent MbUnit features...

Talk Abstract

Red, Green, Refactor!

Starting to unit test your first project is difficult, where to start? What to test? How do you even get started? In this session, Ben starts from scratch and implements an ASP.net 2.0 application using test driven development techniques. The application will have to deal with real world situations such as databases, web services and even some users! Ben will demonstrate how to design the application for testability and how unit testing and mock frameworks can make your life easier and your tests less fragile. At the end, will the tests go green?

Register:  http://www.nxtgenug.net/ViewEvent.aspx?EventID=112

Technorati Tags: ,,

Labels: , ,

MbUnit TypeFixture and Providers

Sunday, January 20, 2008

Continuing in my writing about MbUnit, this post will focus on the TypeFixtureAttribute. The TypeFixture allows a set of tests to focus on testing a certain type of class (generally an interface) and to provide objects of that type to be tested against.

This method is really useful if you have a collection of objects which all have similar behaviour which requires testing. Instead of having to duplicate your test code, you can define the types to be tested with instances of the tests being passed into the test being executed.

In my fake system being tested, I have a collection of objects which all implement a INotNull interface. I need to test to make sure that the implementation of INotNull works correctly, that not nulls are returned when GetNotNullValues() is called. My 'Production' code is this:

public interface INotNull { IEnumerable GetNotNullValues(); }

public class TypeA : INotNull { public override string ToString() { return "TypeA"; }

public IEnumerable GetNotNullValues() { yield return "TypeA"; } }

public class TypeB : INotNull { public override string ToString() { return "TypeB"; }

public IEnumerable GetNotNullValues() { yield return 1; yield return 2; yield return 3; yield return 4; } }

public class TypeC : INotNull { public override string ToString() { return "TypeC"; }

public IEnumerable GetNotNullValues() { yield return new object(); yield return null; yield return new object(); } }

The code looks fine, apart from TypeC which returns a null. In a standard unit testing framework, I would have to create multiple test fixtures for each type in the system and duplicate all of the tests. TypeFixture makes our life easier by allowing us to define a single fixture and test all the objects we want. Let's have a look at the test code.

[TypeFixture(typeof(INotNull), "Tests the INotNull interface.")] #1 public class INotNullTests

Instead of defining a TestFixture at the top of our class, we define a TypeFixture and give it the typeof object we will be testing. We then need to tell it all the objects to use.

[Provider(typeof(TypeA))] #1 public TypeA ProvideTypeA() { return new TypeA(); #2 }

#1 We use the ProviderAttribute and provide the type of object we are returning as a parameter.

#2 We then create a new instance of the object and return it to the caller.

We can use the Provider attribute on as many methods as required to cover all of our objects being tested. The other two objects being tested are TypeB and TypeC.

[Provider(typeof(TypeB))] public TypeB ProvideTypeB() { return new TypeB(); }

[Provider(typeof(TypeC))] public TypeC ProvideTypeC() { return new TypeC(); }

Now we have that in place, we need to write out tests. The test is a standard test, however accepts the type (as defined in the TypeFixture) as a parameter.

[Test] public void TestINotNullValuesNotNull(INotNull instance) { Console.WriteLine(instance.ToString());

foreach (object o in instance.GetNotNullValues()) { Assert.IsNotNull(o, "Instance: {0}. Object was null: {1}", instance, o); } }

We can then use that object within our test to verify it works correctly. This test method will be called once per object defined by a provider attribute. In this case, three tests are executed with TypeC test failing.

image

Adding more tests to the fixture is very quick and easy and with the TypeFixture will result in it being used to test multiple objects. Adding another implementation of the interface is easy as we define another method allowing it to be picked up by all the existing tests.

Technorati Tags: , ,

Labels: , ,

MbUnit Combinational and Factory fixtures

In this post, I want to talk about a little know feature of MbUnit which is the CombinationalTestAttribute.  This was originally described on Peli's blog, but I thought I would revisit the subject.

The combinational test attribute allows us to do pair-wise testing.  This is where we take two inputs (A and B) and test them against each other ({A1, B1}, {A1, B2}, {A1, B3}).

When implementing this system, the OUT (Object Under Test) needs to implement an interface.  In this case a ICount

public interface ICount
{
    int Count(string s);
}

We then implement a X counter which will the number of X's which appear in a string.

public class XCounter : ICount
{
    public int Count(string s)
    {
        int count = 0;
        foreach (char c in s)
            if (c == 'x')
                count++;
        return count;
    }
}

For the purposes of demo'ing, a BadCounter is also implemented.

public class BadCounter : ICount
{
    public int Count(string s)
    {
        return 2;
    }
}

So that would be our production code which we want to test.  Using just standard TestFixture and Test attributes, our tests would have to look something like this:

[TestFixture]
public class ICountTests_Orginal
{
    [Test]
    public void BadCounter_Count_NoX()
    {
        ICount counter = new BadCounter();
        int result = counter.Count("");
        Assert.AreEqual(0, result);
    }

    [Test]
    public void BadCounter_Count_TwoX()
    {
        ICount counter = new BadCounter();
        int result = counter.Count("XX");
        Assert.AreEqual(2, result);
    }

    [Test]
    public void BadCounter_Count_XSpaceYSpaceZ()
    {
        ICount counter = new BadCounter();
        int result = counter.Count("X Y Z");
        Assert.AreEqual(1, result);
    }

    [Test]
    public void XCounter_Count_NoX()
    {
        ICount counter = new XCounter();
        int result = counter.Count("");
        Assert.AreEqual(0, result);
    }

    [Test]
    public void XCounter_Count_TwoX()
    {
        ICount counter = new XCounter();
        int result = counter.Count("XX");
        Assert.AreEqual(2, result);
    }

    [Test]
    public void XCounter_Count_XSpaceYSpaceZ()
    {
        ICount counter = new XCounter();
        int result = counter.Count("X Y Z");
        Assert.AreEqual(1, result);
    }
}

This is only testing the two objects (imagine 100s) with three test cases (imagine 1000s).  This would very quickly become unmanageable and a maintenance nightmare. We can make this much more effective using Combinational.

First part of configuring this is to setup a Factory for the interface.  This will produce all the objects we want to be tested.

[Factory(typeof(ICount))]
public IEnumerable Counters()
{
    yield return new BadCounter();
    yield return new XCounter();
}

Next, we create a factory of test cases.

[Factory(typeof(CombinationTestItem))]
public IEnumerable Strings()
{
    yield return new CombinationTestItem("", 0);
    yield return new CombinationTestItem("aaa", 0);
    yield return new CombinationTestItem("x", 1);
    yield return new CombinationTestItem("xa", 1);
    yield return new CombinationTestItem("xax", 2);
    yield return new CombinationTestItem("X x", 2);
    yield return new CombinationTestItem("X X", 2);
}

I've created a helper class within my code called CombinationTestItem.  This is used just to store the input and expected output so I can access them within my test. This could store as much or as little as you want, only restriction is that the Factory must return IEnumerable.

public class CombinationTestItem
{
    public CombinationTestItem(string value, int xcount) { Input = value; ExpectedOutput = xcount; }
    public string Input;
    public int ExpectedOutput;
}

The last part is to actually create the test.

[CombinatorialTest]                       #1
public void CountIsExact([UsingFactories("Counters")] ICount counter,       #2
                         [UsingFactories("Strings")] CombinationTestItem test)            #3
{
    Assert.AreEqual(test.ExpectedOutput, counter.Count(test.Input));            #4
}

#1 Instead of using [Test] we use [CombinatorialTest]

#2 The first parameter of the test is the Factory of Counters we created.  We use the [UsingFactories] attribute to help the framework understand which factory to pull the data from

#3 Like with #2, we do the same for the test data factory.

#4  Finally, we call the count method on the counter object passed into the test with the value we set on our CombinationTestItem object.  We then verify that it matches the related ExpectedOutput.

When it comes to executing the test cases the framework creates a test for each ICount with each CombinationTestItem test case. The result is 14 test cases (Two ICount objects * 7 CombinationTestItem test cases).

image

Adding additional objects or test cases is simply a case of adding an additional line of code.

My own point about this attribute is that I have never found a real world situation where I have required this.  In theory (like above) it sounds great, but I'm but sure if it would actually solve any of my integration testing problems - I can't imagine it would solve any unit testing problems. If this does solve a problem for you, it would be great to hear about it.

Technorati Tags: , ,

Labels: , ,

DATEPART(WEEK,...) With Linq to SQL

Friday, January 18, 2008

An interesting question was raised on the Linq forums about how to query a date column based on the which week number the date is in.

If we was to write this in SQL, we would use the DATEPART keyword within our WHERE clause. In Northwind, if we wanted to return all the orders which occurred in week 52 we would run the following query.

SELECT * FROM Orders
WHERE DATEPART(ww, OrderDate) = 52

However, in .Net there isn't a simply way to access the Week via DateTime. This makes it difficult for Linq to translate into SQL.

One approach you could take is the easy route and do the query in the database.

CREATE PROCEDURE AllOrdersInWeek52
AS
SELECT * FROM Orders
WHERE DATEPART(ww, OrderDate) = 52

With that, we can included the procedure in our diagram and query it using Linq to SQL. The code below calls the stored procedure and outputs all the dates which match.

public void LinqSproc()
{
    Console.WriteLine("LinqSproc");
    Console.WriteLine("---------------------------------------------------------------");
    DataClasses1DataContext dc = new DataClasses1DataContext();

    var query = dc.AllOrdersInWeek52();

    foreach (var item in query)
    {
        Console.WriteLine(item.OrderDate);
    }
}

The results returned:

ListAllOrdersWithDatesInWeek52
----------------------------------------
23/12/1996 00:00:00
23/12/1996 00:00:00
24/12/1996 00:00:00
25/12/1996 00:00:00
25/12/1996 00:00:00
26/12/1996 00:00:00
27/12/1996 00:00:00
27/12/1996 00:00:00
22/12/1997 00:00:00
22/12/1997 00:00:00
22/12/1997 00:00:00
23/12/1997 00:00:00
23/12/1997 00:00:00
24/12/1997 00:00:00
24/12/1997 00:00:00
24/12/1997 00:00:00
25/12/1997 00:00:00
25/12/1997 00:00:00
26/12/1997 00:00:00
26/12/1997 00:00:00
26/12/1997 00:00:00

Another approach would be to use a Function.  This gives us more control and flexibility within our database.

CREATE FUNCTION dbo.AllOrdersInWeek52Function()
    RETURNS TABLE
AS
RETURN (SELECT * FROM Orders
        WHERE DATEPART(ww, OrderDate) = 52)

That is all very easy because we are just using SQL and calling into our database, if we wanted both could accept the week number as a parameter.  If we wanted to do this solely using .Net we would have to use a custom method to return the week number for the date and then query based on that. The problem with using a custom method is that the query must be performed in memory, as such we need to use the .AsEnumerable().

public void ListAllOrdersWithDatesInWeek52()
{
    Console.WriteLine("ListAllOrdersWithDatesInWeek52");
    Console.WriteLine("---------------------------------------------------------------");
    DataClasses1DataContext dc = new DataClasses1DataContext();

    var query = from o in dc.Orders.AsEnumerable()
                where WeekOf(o.OrderDate) == 52
                select o;

    foreach (var item in query)
    {
        Console.WriteLine(item.OrderDate);
    }
}

private int WeekOf(DateTime? nullable)
{
    if (nullable.HasValue)
    {
        GregorianCalendar gCalendar = new GregorianCalendar();
        int WeekNumber = gCalendar.GetWeekOfYear(nullable.Value, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
        return WeekNumber;
    }
    else
        return 0;
}

As this is occurring for every row in the database, performance will take a hit.  The best solution, is to use a scalar function within the database.

CREATE FUNCTION WeekOfYear(@Date DateTime)
RETURNS Int
AS
BEGIN
RETURN (CAST(DATEPART(ww, @Date) AS INT))
END

Which we can use within our query.

DataClasses1DataContext dc = new DataClasses1DataContext();
var q = from o in dc.Orders
        where dc.WeekOfYear(o.OrderDate) == 23
        select o;

foreach (var item in q)
{
    Console.WriteLine(item.OrderID);
}

This will execute the function inside of the database, resulting in much better performance. The sql produced would look like this:

SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPostalCode], [t0].[ShipCountry]
FROM [dbo].[Orders] AS [t0]
WHERE [dbo].[WeekOfYear]([t0].[OrderDate]) = @p0

I've highlighted the important part.  By using a function, the result is a nice clean quick execution of the query.

Original Question: http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=123&SiteID=1

Technorati Tags: ,

Labels:

NxtGenUG Session - MbUnit

Wednesday, January 16, 2008

Last night I did my MbUnit session at NxtGenUG, Cambridge. Big thank you to everyone who turned up, I hope you all found it useful.

Here are the code and slide deck I used:

Demo Code: http://blog.benhall.me.uk/downloads/NxtGenUG/mbunitdemo.zip

Presentation deck: http://blog.benhall.me.uk/downloads/NxtGenUG/mbunit.pptx

Most of my MbUnit blog posts have been labelled with MbUnit, some of the older ones might have been missed so you might want to use the Google search on the sidebar to search for MbUnit - http://blog.benhall.me.uk/labels/MbUnit.html

Resource Links

www.MbUnit.com

www.TestDriven.NET

Everyone who attended, please fill out the feedback on the NxtGen site - http://www.nxtgenug.net/ViewEvent.aspx?EventID=90

Labels:

Matt W's Windows Workflow Place : .NET 3.5 Beta Exams

Monday, January 14, 2008

This has been mentioned in comments on a previous post before but I didn't know the answer.

The 3.5 Beta exams are still available and apparently can be taken for free - The blog can be found here:

Matt W's Windows Workflow Place : .NET 3.5 Beta Exams

Note to team, these exams are based on WPF, WCF and WF - Wasn't this .Net 3.0?? Should these exams be marked as .Net 3.0 Exams and not 3.5?

Technorati Tags: , , ,

Labels:

DDD6 Feedback

Friday, January 11, 2008

Yesterday I received feedback from my DDD6 talk on Testing applications with MbUnit.  Attendees are asked to leave feedback on the sessions they attended and rate the speaker in four categories; overall, knowledge, presentation and content.  My averages for these where:

Overall Knowledge Presentation Content
4.44 4.77 4.33 4.44

Some of the comments where:

"Was expecting more Gallio stuff, even just more of an introduction to the concepts.. As it was I already knew a lot of"

Fully agree that this was a problem, it's a shame more of Gallio wasn't ready at that point. You can read more about it here and here.

"This guys did a great job. Well-prepared, well-executed and full of useful information."

"Voice projection was an issue at the start, I think this got better as it went on. Some of the content was rushed through, this was probably due to a large subject being tackled in depth in only an hour."

"The speaker clearly knew his stuff. As a result I will be taking a look at MbUnit. A first time presenter, and I'm sure there were a few nerves - did well. "

On a personal note, I think it went OK - but there was/is definitely room for improvement. Thanks for all the feedback, I will take it into account when doing future talks.

Technorati Tags: ,

Labels: ,

Executing MbUnit GUI and Console from Visual Studio

Personally, I use TestDriven.NET to launch the MbUnit GUI to execute my tests.  However, not everyone has that installed.  One alterative approach is to use the External Tools option within Visual Studio.

To create this setting, select the Tools option and select External Tools.

image

You can then Add a new tool and point it at either the GUI or Cons application.

image

The most important settings are the variables to use. First, you need to set the Initial Directory to be the $(BinDir),  this will be where your built assemblies end up and generally is \debug\bin. Next, you need to set what arguments to pass into the MbUnit GUI. $(TargetName)$(TargetExt) will provide you with the assembly name with its extension on the end.  This allows MbUnit to find it in the bin directory and load it successfully.

Just make sure you have your test project selected before selecting the MbUnit option from the menu.

You should find this also works with NUnit and XUnit runners.

Technorati Tags:

Labels:

Alt.Net.UK Registration Open! (Second Batch)

Thursday, January 10, 2008

The Alt.Net.UK registration has opened (well, reopened).  This is the second and final batch of registrations.

To register and for more information visit:

http://www.altnetuk.com

UPDATE: Blog server went down, looks to be back now. Update just to ensure it gets reposted incase anyone missed it.

Technorati Tags: , ,

Labels: ,

MbUnit 2.4 - Rollback, Rollback2 and RestoreDatabaseFirst

Monday, January 07, 2008

One of the interesting features of MbUnit 2.4 is the Rollback attribute.  I've spoke about this in passing in some of my previous posts, but I thought I would drive a little deep into what is going on.

The Rollback attribute can be added to any test method, when the test has finished (either passed or failed) any changes made to the database is rolled back - even if it has transactions inside.  This means that your tests are more isolated

Rollback uses Enterprise services and COM+ and is based on the .Net 1.1 implementation. Rollback2 uses TransactionScope from System.Transactions which was included in .Net 2.0.  If your project is using .Net 2.0, Rollback2 would be the preferred attribute to use.   An example of how this could be used is:

[Test]
[RollBack]
public void GetCategoryByName_NameOfValidCategory_ReturnCategoryObject()
{
    InsertCategory();

    Category c = ProductController.GetCategory("Microsoft Software");

    Assert.AreEqual("Microsoft Software", c.Title);
    Assert.AreEqual("All the latest Microsoft releases.", c.Description);
}

One question I was asked at DDD was if Rollback supports other databases or if its just SQL Server. The answer is, I still haven't been able to find a definitive answer. In theory it should work, but I have read some forum comments about errors when using TransactionScope. If I can get everything setup, I'll write another post with my findings.

While looking around about this feature I came across a RestoreDatabase attribute.  Had to have a play!

Turns out, it allows a backup to be restored before the test is executed (if you didn't get it from the name).  It gets all the information based on the SqlRestoreInfo attribute at the test fixture level and uses that to store the database before the test is executed.

[TestFixture]
[SqlRestoreInfo("Data Source=BIGBLUE;Initial Catalog=Master;Integrated Security=True", "Northwind", "E:\\Northwind.bak")]
public class Class1
{
    string connectionString = "Data Source=BIGBLUE;Initial Catalog=Northwind;Integrated Security=True";

    [Test]
    [RestoreDatabaseFirst]
    public void GetOrders()
    {
        //string queryString = "DELETE FROM dbo.[Order Details];";  If we execute this in the first run the table is empty.
        string queryString = "SELECT * FROM dbo.[Order Details];";  If we execute this in the second run, the data is restored.
        string queryString2 = "SELECT * FROM dbo.[Order Details];";
        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            SqlCommand command = new SqlCommand(queryString, connection);
            SqlCommand command2 = new SqlCommand(queryString2, connection);
            connection.Open();
            command.ExecuteNonQuery();
            SqlDataReader reader = command.ExecuteReader();
            try
            {
                while (reader.Read())
                {
                    Console.WriteLine(String.Format("{0}, {1}",
                        reader[0], reader[1]));
                }
            }
            finally
            {
                // Always call Close when done reading.
                reader.Close();
            }
        }
    }

It's a neat idea and good for integration testing, but I wouldn't recommend it for unit testing as the additional time to restore the database would soon mount up, expect improvements to testing with databases in MbUnit v3.

Technorati Tags:

Labels:

Introduction to XUnit.net Extensions

Following on from my previous post on XUnit I decided to look at the Extensions library associated with the XUnit.net framework.  The XUnit Extensions project is available from http://www.codeplex.com/xunitext and is a separate assembly containing additional attributes (and I guess additional assertions later) and contains some really cool features.

To use the extensions, you need to reference both xunit.dll and xunitext.dll. Currently, there are six main extension attributes included within the assembly.

Theory - Support for Data Driven Tests

The first extensions I am going to look at are a set of extensions categorised as Theories. These theories allow external data to be used as the test data when executing. The extensions assembly has support for the following data providers:

  1. ExcelData
  2. InlineData
  3. OleDbData
  4. PropertyData
  5. SqlServerData

To start with, I will look at the most basic - InlineData.  The InlineDataAttribute allows us to specify data to use within the test, executing the test each time for each attribute - similar to MbUnit's RowTest.  Below is a test which verifies that the length of a string is as expected.

[Theory]
[InlineData("hello", 5)]
[InlineData("hello world", 11)]
[InlineData("failing", 0)]
public void Theory_InLine(string value, int expectedLength)
{
    Console.WriteLine("String:" + value + " With expected length of " + expectedLength);
    Assert.Equal(expectedLength, value.Length);
}

Using TestDriven.NET, each attribute causes a separate test to be executed with the output shown below.

String:hello With expected length of 5
String:hello world With expected length of 11
String:failing With expected length of 0
TestCase 'IntroToXUnitExtensions.Ext.Theory_InLine("failing", 0)'
failed: Assert.Equal() Failure
Expected: 0
Actual:   7
    E:\Users\Ben Hall\Documents\Visual Studio 2008\Projects\IntroToXUnit\IntroToXUnitExtensions\Class1.cs(20,0): at IntroToXUnitExtensions.Ext.Theory_InLine(String value, Int32 expectedLength)

2 passed, 1 failed, 0 skipped, took 1.96 seconds

This is great for reducing the amount of duplicate test code and really helps readability as if you want to add additional test cases you just include another attribute.  Sadly, the ReSharper plugin just thinks this is a single test - instead of three separate tests like TD.net does.  Having it just as a single test makes it difficult to identify the failing test.

image

Moving on, next is the PropertyData attribute.  Property Data allows you to specify a property which returns an IEnumerable<object[]>.  Below is my property which returns the same data as in the above test. I've hard coded the values, but this could some from another source to meet your own requirements.

public static IEnumerable<object[]> MyTestData
{
  get
  {
       yield return new object[] { "hello", 5 };
       yield return new object[] { "hello world", 11 };
       yield return new object[] { "failing", 0 };
  }
}

With the test, you define a PropertyDataAttribute passing in the name of the Property as a string argument.  The test itself then should accept the same parameters as being returned within the object array (in this case, a string and int).  The code to implement this is as below.

[Theory]
[PropertyData("MyTestData")]
public static void Theory_Property(string value, int expectedLength)
{
    Console.WriteLine("String:" + value + " With expected length of " + expectedLength);
    Assert.Equal(expectedLength, value.Length);
}

When it hits the failing test, TD.net outputs the following.  I think this might be a bug as the output isn't as clean as Inline. ReSharper still threats this as a single test.

String:hello With expected length of 5
String:hello world With expected length of 11
String:failing With expected length of 0
TestCase 'M:IntroToXUnitExtensions.Ext.Theory_Property(System.String,System.Int32)'
failed: Exception has been thrown by the target of an invocation.
    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Xunit.EqualException: Assert.Equal() Failure
    Expected: 0
    Actual:   7
    E:\Users\Ben Hall\Documents\Visual Studio 2008\Projects\IntroToXUnit\IntroToXUnitExtensions\Class1.cs(39,0): at IntroToXUnitExtensions.Ext.Theory_Property(String value, Int32 expectedLength)
       --- End of inner exception stack trace ---
.......

Some 'limitations', not sure if limitations is the right word - more rules of usage.  The property must be within the same class as the test being executed and the property must return IEnumerable<object[]<object []>>.  However the advantage of this is what we can reuse the property in multiple different tests instead of redefining the test cases for each test like with Inline.

The next set of attributes pull data from an external location.  The first is ExcelData, this allows us to use a Excel spreadsheet as the source of the data for the tests. By using an excel spreadsheet, we can easily edit and maintain the test data separate to the actual code but it also removes any dependency on having a database setup to hold out test data.  The test with the attribute would look something like below.  You specify the Excel file to use and then a query which will be used to pull the data, the TestData name is actually a Named Range in Excel so the test knows what data to use.

[Theory, ExcelData(@"ExcelTestData.xls", "select * from TestData")]
public void Theory_Excel(string value, int expectedLength)
{
    Console.WriteLine("String:" + value + " With expected length of " + expectedLength);
    Assert.Equal(expectedLength, value.Length);
}

However, the first time I executed this test I got an exception which was something like:

"The Microsoft Jet database engine could not find the object..."

The reason for this was because I hadn't included the ExcelTestData.xls file into the project and set Copy to Output to Copy always.

The file ExcelTestData contains the following, note you must include a header (otherwise your first test case is ignored):

image

To set the data as a named range, right the block of data (including header), right click and select Name a range

image

If you want to edit or delete an existing name, then you need to use the Name Manager under the Formulas tab

image

Important note - it must be a Excel 2003 format - not the 2007 format.

Next is the SqlServerDataAttribute. This allows us to use data within a Sql Server Database and use a SELECT statement to return the test data we want to use within our test code.  This is great when combined with a tool such as Red Gate's SQL Data Generator.

The SqlServerDataAttribute accepts either Server, Database, SelectStatement or Server,Database,Username,Password,SelectStatement.

[Theory]
[SqlServerData("(local)", "IntroToXUnit", "SELECT teststring, expectedLength FROM TestDataTable")]
public void Theory_SqlServer(string value, int expectedLength)
{
    Console.WriteLine("String:" + value + " With expected length of " + expectedLength);
    Assert.Equal(expectedLength, value.Length);
}

One important note, the amount of columns returned from the select statement must match the parameters of the test.

Finally, OleDBDataAttribute works in a similar fashion to SqlServerDataAttribute however allows you to connect to other data sources apart from SqlServer.  The attribute is:

[OleDbDataAttribute(string connectionString, string SelectStatement);

AutoRollback

Similar to MbUnit's Rollback feature, the extensions library has an AutoRollback attribute. By adding this attribute to your test, the entire test will be wrapped within a transaction so once the test has finished (passed or failed) the transaction will be rolled back meaning any changes will be undone.  For example, if we delete the entire customers table, once the test has finished the changes will be rolled back - leaving the database in the same state as before the test.  This is very important for test isolation as we want each test to be independent of any other tests, when it comes to interacting with the database we especially don't want any tests making permanent changes to the database which is used by other tests.

[Fact]
[AutoRollback]
public void AutoRollback()
{
    string connectionString = "Data Source=BIGBLUE;Initial Catalog=Northwind;Integrated Security=True";

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        //SqlCommand command = new SqlCommand("DELETE FROM Customers", connection);
        //command.ExecuteNonQuery();

        SqlCommand command2 = new SqlCommand("SELECT CustomerID FROM Customers", connection);
        SqlDataReader reader = command2.ExecuteReader();
        try
        {
            while (reader.Read())
            {
                Console.WriteLine(String.Format("{0}", reader[0]));
            }
        }
        finally
        {
            // Always call Close when done reading.
            reader.Close();
        }
    }
}

The Rollback attribute also includes additional properties, IsolationLevel, TransactionScopeOption and a Timeout. 

FreezeClock

Unit testing anything to do with the system clock is always difficult!  The problem is that you don't know what time your tests will be executed, and you definitely don't want to limit them to only running at one extract moment.  In my article Beginning to Mock with Rhino Mocks and MbUnit - Part 1: ASP Alliance I spoke about mocking the date time to get around this.

When I first heard about this I was intrigued how they managed to freeze the clock, turns out it wasn't so special - but still useful.  What the extensions framework provides is a Clock class which is a wrapper around the .Net DateTime class.  It properties three properties to access the current DateTime - Now, Today, UtcNow.

In your production code, you use this Clock class instead of DateTime to offer all of your date functionality. When dealing with dates, you would do something like below (of course, instead of outputting to the console you would do something real like query the database).

public class ProductionCode
{
    public void ProcessSomethingInvolvingTime()
    {
        Thread.Sleep(1500);
        Console.WriteLine(Clock.Now);
    }
}

To test this we would then add the FreezeClock attribute, which automatically freezes the Clock object for us. We then use the same Clock.Now method to access the now frozen time.

[Fact, FreezeClock]
public void FrozenProductionCode()
{
    DateTime expected = Clock.Now;
    Console.WriteLine(expected);

    ProductionCode pc = new ProductionCode();
    pc.ProcessSomethingInvolvingTime();
}

Outputting both to the console, we verify that the two dates are actually the same - impossible with the standard DateTime.

07/01/2008 00:48:26
07/01/2008 00:48:26

1 passed, 0 failed, 0 skipped, took 3.56 seconds.

However, I really really don't like the fact that I would have to use the Clock class and reference xunitext within my production code.  Just gives me a nasty feeling and I can't imagine this is how Brad and James wanted it to be used.  Instead, I would prefer to use a type of Dependency Injection (well Date Injection), passing in a DateTime object into the method under test.

public void ProcessSomethingInvolvingTimeDI(DateTime now)
{
    Thread.Sleep(1500);
    Console.WriteLine(now);
}

Our test now looks like this.  Instead of letting the method obtain the time itself we give it the DateTime object (which we got from Clock.Now) to use.

[Fact, FreezeClock]
public void FrozenProductionCodeDI()
{
    DateTime expected = Clock.Now;
    Console.WriteLine(expected);

    ProductionCode pc = new ProductionCode();
    pc.ProcessSomethingInvolvingTimeDI(expected);
}

When we run the test, the date time is still the same and still frozen. However, if we are doing this why not just use the DateTime object itself?

[Fact]
public void DateTimeProductionCodeDI()
{
    DateTime expected = DateTime.Now;
    Console.WriteLine(expected);

    ProductionCode pc = new ProductionCode();
    pc.ProcessSomethingInvolvingTimeDI(expected);
}

I think its something useful, but not sure if I like it.

AssumeIdentity

Assume Identify allows us to change the Current Principal (the user currently executing the assembly).  This is used for various things such as Role management and within CAS (Code Access Security).

[Fact]
public void AssumeIdentityWithoutAttribute()
{
    Console.WriteLine("Username of Thread:" + Thread.CurrentPrincipal.Identity.Name);
}

What is outputted is nothing.

"Username of Thread: "

If we use the AssumeIdentityAttribute, we can pass in a RoleName for which the user executing the test will be a remember of.

[Fact, AssumeIdentity("RoleName")]
public void AssumeIdentityWithAttribute()
{
    Console.WriteLine("Username of Thread:" + Thread.CurrentPrincipal.Identity.Name);
    Assert.True(Thread.CurrentPrincipal.IsInRole("RoleName"));
}

If we run this test, what is outputted is the name of XUnit and IsInRole returns true.

"Username of Thread:xUnit"

If a method we was testing involved CAS as below, the user exectuing the test would have to be a remember of that role - not always the case for build servers.

[PrincipalPermission(SecurityAction.Demand, Role = "Administrators")]
public void AdminOnly()
{
    Console.WriteLine("Executing....");
}

With AssumeIdentity, the test can correctly execute the method.

[Fact, AssumeIdentity("Administrators")]
public void AssumeIdentityCAS()
{
    ProductionCode p =new ProductionCode();
    p.AdminOnly();
}

Trace

Adding Trace attribute to your tests causes the test name to be wrote out to the Trace listener before and after the test is being executed. Useful for debugging if your tests have a habit of stopped mid-execution.

RunWithNUnit

Finally, the RunWithNUnit attribute. This method actually lives in the xunitext.nunit.dll assembly.  To check that I wasn't going made, I created a separate project referencing NUnit 2.4, XUnit and XUnitExt.NUnit.  I then use the XUnit console to make sure I'm executing under XUnit.

The code should look something like this:

[XunitExt.NUnit.RunWithNUnit]
[NUnit.Framework.TestFixture]
public class OldNUnitTests
{
     [NUnit.Framework.Test]
     public void RunWithNUnit()
     {
          NUnit.Framework.Assert.AreEqual("Running with NUnit", "Running with NUnit");
     }
}

However, I couldn't get this to work correctly as I kept receiving an "error: Exception has been thrown by the target of an invocation. in TargetInvocationException" exception.  I posted on the forum, but at the time of posting no reply.

RunWithNUnit throws exception

In summary, I hope you have found this post useful when getting started using XUnit.net and their extensions. Any feedback/comments then please leave a comment on the post.

Technorati Tags: , ,

Labels: , ,

Introduction to XUnit

Sunday, January 06, 2008

While MbUnit is my unit testing framework of choice, I've heard some good reports about XUnit so I decided to take a closer look.  XUnit is a unit testing framework for the .Net platform, created by Brad Wilson and James Newkirk (One of the original developers of NUnit, both currently working for Microsoft) and is available to download from http://www.codeplex.com/xunit.  The framework itself is built using .Net Framework 2.0, doesn't require any installation (XCopy) which makes it great for storing in source control and includes a TestDriven.NET runner, ReSharper runner and a console runner for executing the tests.

This framework takes a major departure from the other frameworks currently around. The major change is the naming of the attributes which you add to your test methods. Using MbUnit\NUnit, your test fixture would look something like:

[TestFixture]
public class MbUnitAccountTests
{
    [TestFixtureSetUp]
    public void TestFixtureSetup()
    {
        Console.WriteLine("We are currently in the constructor");
    }

    [Test]
    public void MyFirstTest()
    {
        Console.WriteLine("We are currently in my first test - well done!");
        Assert.IsTrue(true);
    }

    [Test]
    public void MyFirstFailingTest()
    {
        Console.WriteLine("We are currently in my first failing test - not so well done!");
        Assert.IsTrue(false);
    }

    [TestFixtureTearDown]
    public void TestFixtureTeardown()
    {
        Console.WriteLine("We are currently disposing.");
    }
}

However, using XUnit your tests would look something like this:

public class AccountTests : IDisposable   #1
{
    public AccountTests()                          #2
    {
        Console.WriteLine("We are currently in the constructor");
    }

    [Fact]                                                   #3
    public void MyFirstTest()
    {
        Console.WriteLine("We are currently in my first test - well done!");
        Assert.True(true);
    }

    [Fact]
    public void MyFirstFailingTest()
    {
        Console.WriteLine("We are currently in my first failing test - not so well done!");
        Assert.True(false);
    }

    public void Dispose()                           #4
    {
        Console.WriteLine("We are currently disposing.");
    }
}

#1 - The first change is that we don't need to add a TestFixture attribute to our class. Also, XUnit doesn't have any Test or TestFixture Setup and Teardown attributes, however it does allow you to take advantage of the constructor and the Dispose method (if it implements IDisposable) so you can configure anything before the tests start executing.  You can't have methods executing before and after each test separately.  The aim of this is to improve test isolation and to make the tests more readable.

#2 - As mentioned above, we use the constructor for the test class to setup anything

#3 - Before, we would say that a method would be a Test.  With XUnit they have taken a different approach and says that TDD is about example driven development and not actually testing (which I agree with to a point) as we use the methods to express intent of the class. By using FactAttribute, we are saying that this is true for this example.

#4 - As mentioned, we use Dispose to clean up anything once the tests have executed.

If we execute the above test cases using the ReSharper plugin, the output would be like below. If you look closely at the output, you can see we are constructing and disposing the test object for EACH TEST. MbUnit\NUnit creates the object once and calls the test methods on the same object. Having an object per test improves the test isolation.

image

XUnit does however support a type of Test Setup - just not as we know it. In the code below, we create SomeFixture with a method.  We then use the IUseFixture interface to inject the fixture into the test class. Within the SetFixture method (which is on the interface), we can call any method on the SomeFixture object.

public class SomeFixture
{
    public void SomeMethod()
    {
        Console.WriteLine("SomeFixture.SomeMethod()");
    }
}

public class AccountTests : IUseFixture<SomeFixture>, IDisposable
{
    public void SetFixture(SomeFixture data)
    {
        Console.Write("SetFixture? \t ");
        data.SomeMethod();
    }
//...Your Tests
}

Now if we execute the tests, you can see the method is being called and outputted without us writing any additional code.

image

Moving on, the framework comes a good selection of assertions.  The assertions included are:

  • Contains and Contains<T>
  • DoesNotContain and DoesNotContain<T>
  • Empty
  • Equal<T>
  • False
  • InRange<T>
  • IsNotType and IsNotType<T>
  • IsType<T>
  • NotEmpty
  • NotEqual<T>
  • NotInRange<T>
  • NotNull
  • NotSame
  • Null
  • Same
  • Throws and Throws<T>
  • True

The framework takes full advantage of generics.  Most of them are pretty standard, but two I want to pay special attention to is InRange<T> and Throws<T>.

Firstly, InRange is an interesting method and something which I have really wanted in the past.  The method takes three arguments, the actual value being tested and then the min/max value which the value should be in.  This checks that the actual value is between the two values.  This is useful when you know it should be in an range but you don't care what the value actually is.

The first is a very simply test which tests to see if myValue is inbetween the min and max values.

[Fact]
public void InRangeInt()
{
    int myValue = 100;
    int min = 1;
    int max = 10;
    Assert.InRange(myValue, min, max);
}

This fails (of course...). The output from TD.net is as follows:

TestCase 'IntroToXUnit.Tests.AccountTests.InRangeInt' failed: Assert.InRange() Failure
Range:  (1 - 10)
Actual: 100
    E:\Users\Ben Hall\Documents\Visual Studio 2008\Projects\IntroToXUnit\IntroToXUnit\Class1.cs(49,0): at IntroToXUnit.Tests.AccountTests.InRangeInt()

This also works with other objects, for example, below does the same thing but with dates.

[Fact]
public void InRangeDateTime()
{
    Assert.InRange(new DateTime(2009, 1, 1), new DateTime(2000, 1, 1), new DateTime(2008, 1, 6));
}

As such, the failing message is this:

TestCase 'IntroToXUnit.Tests.AccountTests.InRangeDateTime'
failed: Assert.InRange() Failure
Range:  (01/01/2000 00:00:00 - 06/01/2008 00:00:00)
Actual: 01/01/2009 00:00:00
    E:\Users\Ben Hall\Documents\Visual Studio 2008\Projects\IntroToXUnit\IntroToXUnit\Class1.cs(55,0): at IntroToXUnit.Tests.AccountTests.InRangeDateTime()

The method also has a parameter which accepts a IComparer<T> so you can customize how the checking is done.

The Throws<T> is another departure from traditional unit testing frameworks.  Instead of saying you expect a particular exception to be thrown from somewhere in the test case, you actually define the line of code that you expect to throw the exception - again, improving readability as we know the exact call to expect the exception to be raised from.  As an example, we are testing the following method. 

public void Withdraw(decimal amount)
{
    if(amount <= 0)
        throw new ArgumentException();

    Balance += amount;
}

Using XUnit, the test we would write would look something like below.  When we call a.Withdraw(0), we wrap the call inside a delegate and pass it as a parameter to the Assert.Throws class.  We then define the type of exception we expect to be thrown as the type for the method, in this case ArgumentException.

[Fact]
public void Withdraw_Amount0_ThrowsArgumentException()
{
    Account a = new Account();
    a.Balance = 1000;

    Assert.Throws<ArgumentException>(delegate { a.Withdraw(0);});
}

This passes successfully.  If we call a different method (one which doesn't throw the exception).

[Fact]
public void Withdraw_Amount0_ThrowsArgumentException_Fails()
{
    Account a = new Account();
    a.Balance = 1000;

    Assert.Throws<ArgumentException>(delegate { a.WithdrawWithOutException(0); });
}

Then the test fails with the following error:

TestCase 'IntroToXUnit.Tests.AccountTests.Withdraw_Amount0_ThrowsArgumentException_Fails'
failed: Assert.Throws() Failure
Expected: System.ArgumentException
Actual:   (No exception was thrown)
    E:\Users\Ben Hall\Documents\Visual Studio 2008\Projects\IntroToXUnit\IntroToXUnit\Class1.cs(76,0): at IntroToXUnit.Tests.AccountTests.Withdraw_Amount0_ThrowsArgumentException_Fails()

The final thing I want to talk about is other common scenarios, such as Ignore and Timeout for tests.  Both Skip and Timeout are parameters on the Fact attribute. If you want a test to be skipped, then you set the Skip attribute and give a reason.

[Fact(Skip = "Takes too long")]
public void SkippedTest()
{
    //Never executed.
}

When the test is executed, the following will be outputted.

TestCase 'IntroToXUnit.Tests.AccountTests.SkippedTest' not executed: Takes too long

0 passed, 0 failed, 1 skipped, took 2.18 seconds.

Timeout is set in a similar fashion, but you give it the timeout in milliseconds.  Below, we want the test to timeout after 1 seconds.

[Fact(Timeout = 1000)]
public void TimeoutTest()
{
    Thread.Sleep(5000);
}

Once the timeout is reached, it fails and the output is as follows.

TestCase 'IntroToXUnit.Tests.AccountTests.TimeoutTest' failed: Test execution time exceeded: 1000ms

0 passed, 1 failed, 0 skipped, took 4.15 seconds.

In summary, that has been a quick summary of XUnit and what it can offer. The framework has some really interesting concepts, but I don't know if its ready for a full production test suite just yet.  It will be interesting to see what Brad and James does once 1.0 is released.

Technorati Tags: , ,

Labels: , ,

Custom Insert logic with Linq to SQL

Friday, January 04, 2008

On the forums, it was asked how to have your own custom logic for the insert process, for example using a stored procedure to insert the object.

One approach is to redefine the insert behaviour within the designer inside Visual Studio 2008.  For these examples, I'm going to be the Category table in Northwind.

Firstly, create your stored procedure which accepts all the properties on the object as arguments.  The stored procedure needs to have a special OUTPUT parameter.   This output parameter should return the ID of the row being inserted so Linq can re-populate the ID for the object and track any future changes.

CREATE PROCEDURE [dbo].[InsertCategory]
@categoryID INT OUTPUT,
@categoryName nvarchar(15),
@description ntext,
@picture image
AS

INSERT INTO [Northwind].[dbo].[Categories]
           ([CategoryName]
           ,[Description]
           ,[Picture])
     VALUES
           (@categoryName
           ,@description
           ,@picture)

SET @CategoryID = CAST (SCOPE_IDENTITY() as Int)

Information on why to use Scope Identity vs Identity can be found here.

Then, drag it onto the designer so it is a method on the data context.

image

Then, select the category table on your designer surface (add it if required). In the properties window, you can set the action to be taken for Delete, Insert and Update.  Select insert and click the button on the property.

image

The Configure Behaviour form will then be displayed. Here, you can select to Customize the action, and then select the stored procedure to use on the data context.  If should then auto configure the parameters for the sproc, but you manually do this stage if required.

image

At this point, whenever you insert a Category and call SubmitChanges, the stored procedure will be used instead of Linq's own code. You can do configure update and delete in a similar fashion. However, with update sprocs you can access in the original data values as well as the updated data.

The other approach is to use the partial methods feature of C# 3.0.  In a partial class for your DataContext, you add the partial method for InsertCategory which calls your stored procedure on the data context.

partial void InsertCategory(Category instance)
{
    System.Nullable<int> nullableID = instance.CategoryID;
    this.InsertCategory(ref nullableID, instance.CategoryName, instance.Description, instance.Picture);
    instance.CategoryID = nullableID.GetValueOrDefault();
}

Another approach is just to have ADO.net code but I think the above method is neater.

partial void InsertCategory(Category instance)
{
    SqlConnection sqlConn = new SqlConnection(global::LinqPOC.Properties.Settings.Default.NorthwindConnectionString);
    SqlCommand sqlCmd = new SqlCommand("InsertCategory", sqlConn);
    //Setup Parameters for sproc
    try
    {
        sqlConn.Open();
        int insertedID = (int)sqlCmd.ExecuteScalar();
        instance.CategoryID = insertedID;
    }
    finally
    {
        sqlConn.Close();
    }
}

Which approach should you use? Well, under the covers they are very similar. Instead of having a partial method within the designer, as below.

partial void InsertCategory(Category instance);

There is a private InsertCategory implementation. This takes the category object being inserted, calls the stored procedure as a method on the datacontext and then repopulates the CategoryID

private void InsertCategory(Category obj)
{
    System.Nullable<int> p1 = obj.CategoryID;
    this.InsertCategory(ref p1, obj.CategoryName, obj.Description, obj.Picture);
    obj.CategoryID = p1.GetValueOrDefault();
}

As such, it just depends on if you want to implement the method yourself or have the designer do it for you.

Forum post: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2592415&SiteID=1

Technorati Tags: ,

Labels:

Linq Quickly: Book Review

Wednesday, January 02, 2008

Linq Quickly

Recently I was sent a copy of a new book entitled Linq Quickly.  The book is available from Packt Publishing wrote by N. Shateesh Kumar.  This book is for a .Net developer with all the code samples in C#.  The book covers the main aspects for the Linq framework including:

  • LINQ to Objects
  • LINQ to XML
  • LINQ to SQL
  • LINQ to DataSets
  • LINQ to XSD

    The book itself is 225 pages and provides a good introduction into the Linq framework.  The book itself starts by introducing the architecture of Linq and some of the language features of C# 3.0.  It then moves on to discuss Linq to Objects providing the reader with a foundation of linq.  It then touches on Linq to XML which was interesting and provided a good foundation and introduction. There is then a large section of the book on Linq to SQL, which I would expect as its a major part of the framework and the book discusses the concepts with code examples.  Finally, it talks about DataSets and XSD.

    The last chapter is more of a reference guide to the different extension methods provided by the framework which is a good summary of everything and an example of how to implement and use the method.

    My main problem with the book is that there are a number of typos and small things which should easily have been picked up by the reviewer/author.  For example it refers to Linq as being part of the .Net framework 3.0.  As everyone knows, it was part of .Net 3.5.  It does let the book down.  The book is also based on pre-rtm syntax, but that isn't really a problem as there wasn't any major changes.

    In summary, the book provides a good introduction/quickstart to the Linq stack and if you want a gentle introduction to the different sections and how they fit together then its great. If you want something more in-depth then definitely look at Linq in Action (sadly, I only have that in ebook format) but this book does aim at a different reader. I'm sure I will refer back to it to lookup some syntax.

    Linq in Action Review: Ben Hall's Blog- LINQ In Action Book - Early Review

    Website and purchase: http://www.packtpub.com/linq-quick-starter/book

    Technorati Tags: ,
  • Labels:

    Alt.Net.UK Registration Open! (First Batch)

    The moment you have all been waiting for I'm sure.  The Alt.Net.UK registration has opened.  We have limited this first batch of registrations, next batch will open very shortly.

    To register visit:

    http://www.altnetuk.com

     

    Technorati Tags: , ,

    Labels: ,

    Happy 2008!

    Tuesday, January 01, 2008

    Well, it's the end of another year, last year I did a post to summarise the year and plans for the next year so I thought I would review my progress.  It's been a very interesting year with lots of different things happening.  Just some of the things technically based I have done:

    1. Made a snowman, wonder if we will get enough snow to do that again this year - We had a snow baby and his name is Frosty
    2. Finished 3rd in the UK round of the Imagine Cup - Ben Hall's Blog- Imagine Cup 2007 UK Final -- Herts of Code
    3. Joined Red Gate - Graduate Test Engineer @ Red Gate Software
    4. Held a Vista and Office Launch on campus - University of Hertfordshire Vista and Office Launch
    5. Gave a few nuggets at NxtGenUG Coventry.
    6. Graduated from University of Hertfordshire with a First.  Also won a University prize for academic achievements and the Imagine Cup.
    7. Spoke at DDD6 on MbUnit
    8. Wrote two articles on Rhino Mocks
    9. Wrote 220 blog posts
    10. Attended TechEd Europe
    11. Started planning Alt.Net.UK

    So what do I have planned for 2008?  Here are just a few things I really want to do.

    1. Speak at NxtGenUG next month.
    2. Alt.Net.UK Conference
    3. DDD7.... I will submit one or two sessions. 
    4. Blog more - I want to hit the 300 posts in a year...
    5. Achieve my MCTS in SQL Server 2005.
    6. Learn more about SQL Server 2008.
    7. Release some software... Don't know what, but something simply but effective.
    8. Produce more screencasts
    9. Write more articles
    10. Maybe speak somewhere else. Need to decide what to speak on...
    11. Play on my XBox 360 more.
    12. As a developer, I want to better understand the low level aspects of software development (threads, JIT, Garbage collection - generally the CLR and DLR better). I also want to improve my high level understanding (patterns and practices).
    13. As a tester, I want to improve my skill at writing automated tests.  I also want to improve my manual testing abilities.
    14. Read more code. I want to start reading more open source code from various different projects to help point 12 and 13.
    15. Learn Ruby/IronRuby

    Wonder how many of them I will actually get done...

    Labels: