MbUnit

Gallio v.3.2.2 resolves problem with CS1685 warning.

I was very pleased when I saw a Yann Trevin’s post about new version of Gallio and MbUnit.  What made me happy about this release is that the team resolved issue with CS1685 warning.  After I downloaded Gallio v3.2.2 and remove my temporary fix that deals with CS1685 warning, I was able to confirm the problem is gone.  If you’re using Gallio / MbUnit, go to Downloads page and get the msi for your system.

Advertisements
.Net, MbUnit

MbUnit 3.2 makes it easier to work with Xml

In my previous article I mentioned about upcoming new release of Gallio /  MbUnit.  Feel free to download the Release Candidate and try it for yourself.  In this post I’ll talk about another new feature.

Not everybody like XML but everyone had to work with it. It’s used for many different purposes. Most people use it for configuration like web.config or .csproj / .vbproj. Some people use this format for data, others for communication. I believe that it’s going to be very hard to find a .NET developer that didn’t work with XML. If you do work with XML and you like to unit test your code, than I have good news for you. With new upcoming version 3.2 of MbUnit you are going to get better support to unit test your XML code. The Gallio team gives us three new Assert methods to test XML:

  • Assert.Xml.AreEqual
  • Assert.Xml.Exists
  • Assert.Xml.IsUnique

Assert.Xml.AreEqual

Let start by showing a simple and probably very obvious example:

        [Test]
        public void TestXmlAreEqualWithString()
        {
            const string xmlString =
                "<Books>" +
                "  <Book title='C# in Depth' />" +
                "  <Book title='Learing C#' />" +
                "</Books>";

            Assert.Xml.AreEqual(xmlString, XElement.Load(new StringReader(xmlString)).ToString());
        }

In the example above we’re comparing XML strings.  There’s another overload that instead of strings takes TextReader objects.

        [Test]
        public void TestXmlAreEqualWithTextReader()
        {
            const string xmlString =
                "<Books>" +
                "  <Book title='C# in Depth' />" +
                "  <Book title='Learing C#' />" +
                "</Books>";

            TextReader textReaderXml = new StringReader(xmlString);
            Assert.Xml.AreEqual(
                new StringReader("<Books><Book title='C# in Depth'/><Book title='Learing C#'/></Books>"),
                textReaderXml);
        }

As you can see, the formatting of XML is different, but our test still succeeds since it represents the same XML.

Let’s now make a small test.  We know that XML is case-sensitive  language.  What is going to happen if you we mismatch case?  Let’s make expected value for one of the book title ‘Learning c#’ instead of ‘Learning C#’.

        [Test]
        public void TestXmlAreEqualWithString()
        {
            const string xmlString =
                "<Books>" +
                "  <Book title='C# in Depth' />" +
                "  <Book title='Learing C#' />" +
                "</Books>";

            Assert.Xml.AreEqual(
                "<Books><Book title='C# in Depth'/><Book title='Learing c#'/></Books>",
                XElement.Load(new StringReader(xmlString)).ToString());
        }

After executing this test, we will see the following error that conveniently highlights the problem area:

AreEqual_error

Wait a second.  But what if in my application I don’t care about case-sensitivity for my data?  Well, in this case guys from the Gallio team provided us with an optional parameter of type XmlOptions.  Therefore, if we add XmlOptions.Loose parameter to our Assert.AreEqual, our test is going to pass.

            Assert.Xml.AreEqual(
                "<Books><Book title='C# in Depth'/><Book title='Learing c#'/></Books>",
                XElement.Load(new StringReader(xmlString)).ToString(), 
                XmlOptions.Loose);

You can find more information on XmlOptions in the Gallio Wiki site.

 

Assert.Xml.Exists

This assertion method checks if an element or an attribute can be found in a specific XML document.

  • The first parameter of Assert.Xml.Exists method is an Xml document.   Like in Assert.Xml.AreEqual method you can represent Xml document as a string or a TextReader object. 
  • The second parameter is an Xml Path that can be either a string in format “/element[/element]:attribute” or an object that implements IXmlPathLoose interface.
  • The third parameter is already familiar to us XmlOptions object.

Let’s look at a specific example where will check if Book element exists. 

        [Test]
        public void TestXmlExistsForElement()
        {
            const string xmlString =
                "<Books>" +
                "  <Book title='C# in Depth' />" +
                "  <Book title='Learing C#' />" +
                "</Books>";

            // Xml Path as a string
            Assert.Xml.Exists(xmlString, "/Books/Book", XmlOptions.Default);
            // Xml Path as a IXmlPathLoose
            Assert.Xml.Exists(xmlString, XmlPath.Element("Books").Element("Book"), XmlOptions.Default);
        }

For completeness let’s show a separate example where we will be looking for title attribute.

        [Test]
        public void TestXmlExistsForElement()
        {
            const string xmlString =
                "<Books>" +
                "  <Book title='C# in Depth' />" +
                "  <Book title='Learing C#' />" +
                "</Books>";

            // Xml Path as a string
            Assert.Xml.Exists(xmlString, "/Books/Book:title", XmlOptions.Default);
            // Xml Path as a IXmlPathLoose
            Assert.Xml.Exists(xmlString, XmlPath.Element("Books").Element("Book").Attribute("title"), XmlOptions.Default);
        }

In case an element or an attribute not found, Gallio will produce an error message similar to the one below:

Exists_error

Assert.Xml.IsUnique

This method takes the same parameters as Assert.Xml.ExistsAssert.Xml.IsUnique fails if an element is encountered more than once in Xml document.  I expect that you will not utilize this method as much as other two methods.

The following code is going to fail because we have two Book elements in out Xml.

        [Test]
        public void TestXmlIsUnique()
        {
            const string xmlString =
                "<Books>" +
                "  <Book title='C# in Depth' />" +
                "  <Book title='Learing C#' />" +
                "</Books>";

            // Xml Path as a string
            Assert.Xml.IsUnique(xmlString, "/Books/Book", XmlOptions.Default);
            // Xml Path as a IXmlPathLoose
            Assert.Xml.IsUnique(xmlString, XmlPath.Element("Books").Element("Book"), XmlOptions.Default);
        }

Here’s our error message:

IsUniqe_error

Last words.

I hope you find it useful and I didn’t waste mine and your time because my wife and kids never going get this hour back.

 Gallio wiki site is a great place to learn more about XML AssertionsGallio / MbUnit is an open source project and they always looking for new contributors.  If you consider joining the project, click here to learn how.

kick it on DotNetKicks.com

.Net, MbUnit

Assert.Count in MbUnit version 3.2

The Gallio team is about to release version 3.2 of Gallio and MbUnit.  If you’re impatient and like to eat your cake hot before it cools down, then download the Release Candidate.  The new version has many new great features.  Click here to see the list of enhancements and here for the bug fixes.

One of the new features is Assert.Count.  It’s impossible to count how many times I wrote code that verifies number of items in the specified collection:

        [Test]
        public void Test()
        {
            var list = new List<int> {2, 3, 5};
            Assert.AreEqual(3, list.Count);
        }

Now with new 3.2 version I can write my code like this:

        [Test]
        public void TestCount()
        {
            var list = new List<int> { 2, 3, 5 };
            Assert.Count(3, list);
        }

I assume that for most people it doesn’t look like a huge improvement and it’s probably not, but it definitely makes code more readable and defines clear the intentions of the specific assertion.

I don’t expect to surprise anybody by telling you that it also works with arrays.

        [Test]
        public void TestArray()
        {
            Assert.Count(3, new[] { 1, 2, 3 });
        }

Actually it works with any object that implements IEnumerable interface even if doesn’t have Count or Length property like CredentialCache class.

        [Test]
        public void TestEnumerable()
        {
            var myCache = new CredentialCache
                         {
                             {
                                 new Uri("http://www.contoso.com/"),
                                 "Basic",
                                 new NetworkCredential("userName", "password")
                             },
                             {
                                 new Uri("http://www.contoso.com/"),
                                 "Digest",
                                 new NetworkCredential("userName", "password", "domain")
                             }
                         };
            Assert.Count(2, myCache);
        }

It even works with string types (of course it does, string also implements IEnumerable).

        [Test]
        public void TestString()
        {
            Assert.Count(5, "Vadim");
        }

kick it on DotNetKicks.com

ASP.NET MVC, MbUnit

ASP.NET MVC template for MbUnit tests needs to be fixed.

There’re so many new technologies and tools appearing all the time that it’s impossible to keep up. 

First time I looked at ASP.NET MVC framework was more than a year ago when Microsoft just released the first Beta.  I really liked the new web framework for decoupling and testability. However, because I didn’t have any project where I could use it I left it alonge and started playing with some other toys like WPF and Silverlight.  Now my company is starting developing using ASP.NET MVC framework and it’s time for me get familiar with it again.

So I updated my ASP.NET MVC Beta with RC1.  As a next step I created a sample site using ASP.NET MVC Web Application template.

mvc template

When I was asked if I want to create unit tests, I couldn’t say NO.  As a unit test framework I chose MbUnit v3.

mvc mbUnit

After all the default files were generated by the template, I compiled the solution before making any modifications.  I was surprised when the solution failed to compile.   I got the following errors:

mvc errors

As soon as I look at these errors I realized that I’m missing the following using statements:

using System.Web.Mvc;
using MyNamespace.Controllers;

After adding the missing statements, the solution compiled without any problems.

It’s not a hard problem for a developer to correct but I hope that ASP.NET MVC team will fix the template before they ship the final “1.0” release.

kick it on DotNetKicks.com

.Net, C#, MbUnit, Reference Type, TDD

Comparing Reference Types in Unit Tests.

If you’ve done some unit testing, you’re familiar with Assert.AreEqual method.  Have you try to compare two objects that have the same value(s) but the AreEqual method tells you that they are not equal?  For example let assume that we have a class Point:

   1: private class Point
   2: {
   3:   private int _x;
   4:   private int _y;
   5:  
   6:   public Point(int x, int y)
   7:   {
   8:     _x = x;
   9:     _y = y;
  10:   }
  11: }

And we test for the constructor:

   1: [Test]
   2: public void Point_constructor_test()
   3: {
   4:   Point point = new Point(2, 3);
   5:   Assert.AreEqual(point, new Point(2, 3));
   6: }

When I run this test using MbUnit, the assertion fails.  The reason it fails because Point is a reference type.     Actually what is getting compared is objects references (not objects values) and of course they have different references.

One way we could fix it is to make Point a Value Type by replacing class with struct.

   1: private struct Point
   2: {
   3:   private int _x;
   4:   private int _y;
   5:   
   6:   public Point(int x, int y)
   7:   {
   8:     _x = x;
   9:     _y = y;
  10:   }
  11: }

This definitely resolves the issue.

Another thing we could do is implement IEquatable<T> interface:

   1: private class Point : IEquatable<Point>
   2: {
   3:   private int _x;
   4:   private int _y;
   5:  
   6:   public Point(int x, int y)
   7:   {
   8:     _x = x;
   9:     _y = y;
  10:   }
  11:  
  12:   public bool Equals(Point other)
  13:   {
  14:     return (_x == other._x) && (_y == other._y);
  15:   }
  16: }

[Updated] However, MbUnit test still will fail because deep inside MbUnit’s AreEqual calls object.Equal(object).  In order for AreEqual to succeed in this case, it needs to call generic version of AreEqual.  Something like this:

   1: private static bool AreEqual<T>(T expected, T actual)
   2: {
   3:   if (expected is IEquatable<T> )
   4:     return ((IEquatable<T>)expected).Equals(actual);
   5:   return expected.Equals(actual);
   6: }

It means we need to modify our test little bit. Instead of AreEquals method we can use IsTrue one.

   1: [Test]
   2: public void Point_constructor_test()
   3: {
   4:   Point point = new Point(2, 3);
   5:   Assert.IsTrue(point.Equals(new Point(2, 3)));
   6: }

In software development the same problem can be solved many different ways.  I assume that most common solution is going to be comparing some public properties in the object instead of the whole object.

Let assume assume that our Point class has public properties X and Y.  Here’s an example how my test would look:

   1: [Test]
   2: public void Point_constructor_test()
   3: {
   4:   Point point1 = new Point(2, 3);
   5:   Point point2 = new Point(2, 3);
   6:   Assert.AreEqual(point1.X, point2.X);
   7:   Assert.AreEqual(point1.Y, point2.Y);
   8: }

kick it on DotNetKicks.com

.Net, C#, Coding, MbUnit, Rhino.Mocks, TDD

Mock DataTable

Today I had to work with some legacy code.  It was originally written in Delphi and then converted line by line to C#.  Before changing anything in the code I decided to create unit tests and make sure that I have 100% coverage.

One of the thing I had to do in my unit test is to mock DataTable.  Here are the steps I made during mocking.

  1. Create needed columns in a DataTable.
  2. Create a new DataRow.
  3. Assign values to the row.
  4. Finally add the row to the DataTable.

Repeat steps 2- 4 for each row you want to add to your DataTable.

Here’s the example:

   1: [Test]
   2: public void HolidayTest()
   3: {
   4:   MockRepository mocks = new MockRepository();
   5:   ICompanyDAL dalMock = mocks.CreateMock<ICompanyDAL>();
   6:   // Create DataTable
   7:   DataTable fakeHolidays = new DataTable();
   8:   // 1. Add Columns
   9:   fakeHolidays.Columns.Add("Holiday", typeof (DateTime));
  10:   fakeHolidays.Columns.Add("Name", typeof(string));
  11:   // 2. Create new DataRow
  12:   DataRow dayRow = fakeHolidays.NewRow();
  13:   // 3. Assign values to the row
  14:   dayRow["Holiday"] = DateTime.Parse("07/04/2008");
  15:   dayRow["Name"] = "Independence Day";
  16:   // 4. Add the row to the DataTable
  17:   fakeHolidays.Rows.Add(dayRow);
  18:   _pgDate.CompanyDal = dalMock;
  19:   using (mocks.Record())
  20:   {
  21:     Expect.Call(dalMock.GetHolidays()).Return(fakeHolidays);
  22:   }
  23:   using (mocks.Playback())
  24:   {
  25:     DataTable holidays = _pgDate.Holidays;
  26:     Assert.GreaterThan(holidays.Rows.Count, 0);
  27:   }
  28: }

I used Rhino.Mocks as my mocking framework in the example above.

kick it on DotNetKicks.com