Per Erik Strandberg /cv /kurser /blog

Inspired of the Python Unit Test I want to do unit testing for .NET. I've heard that this is really easy in Sharp Develop (see [1] for a short introduction). (Apparently this is also possible in Visual Studio - or is it?)

Why do unit testing?

I can't say it better than Martin Aspeli does in [2] so I'll just quote him: "[Unit testing is] the only way of even remotely convincing your customers and friends your code doesn't completely suck."

Also unit testing is:

So what is unit testing?

Test driven development is about first writing tests. And then writing code. It is like when you start a course you get a pack of old exams and you only study stuff to pass the old exams. When you then have your real exam you should be able to pass it if you were able to pass the old exams.

Read More

Example of Unit testing with NUnit in Sharp Develop

NUnit is an open source unit testing framework written in C#, download and install from [7] .

In this simple example we will implement rövarspråket ([8]) in a library. To get started we just:

  1. Start Sharp Develop (see Sharp Develop to find a download link).
  2. Create a new solution.
  3. Add a reference to nunit.framework that you should find in the GAC: http://www.pererikstrandberg.se/blog/dot-net-unit-test/gac-nunit-framework.png
  4. Right click the project and add a new item: and add a unit test: http://www.pererikstrandberg.se/blog/dot-net-unit-test/nunit-add-item.png
  5. This will create a blank test file with one blank test. To test the test change the comment into something like this: Assert.IsTrue(false, "This will always fail :)");
  6. You should now get a little window to the right with the unittest: http://www.pererikstrandberg.se/blog/dot-net-unit-test/nunit-test-view.png
  7. Running all tests should now give an error similar to this: This will always fail :), Expected: True, But was: False ... Also notice that there are red things to the right - read means bad.

Back to Rövarspråket

I make a skeleton rorovovaror.cs with an intentional missing f in the consonants.

using System;

namespace rorovovaror
{
    static class rovar
    {
        static string lower_consonants = "bcdghjklmnpqrstvwxz";
        static string upper_consonants = "BCDGHJKLMNPQRSTVWXZ";

        public static string enrov(string normal)
        {
            return "";
        }

        public static string derov(string rov)
        {
            return "";
        }
    }
}

I make a little list of known test cases and make test the conversion to and from rovar:

using System;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;

namespace rorovovaror
{
    [TestFixture]
    public class rorovovaror_test
    {		
        string[][] testPairs =  new string[][] {
            new string[] {"rov", "rorovov"},
            new string[] {"Test",      "TOTesostot"},
            new string[] {"IBM",       "IBOBMOM"},
            new string[] {"fooBAR",    "fofooBOBAROR"},
            new string[] {"XYZZYX",    "XOXYZOZZOZYXOX"},
            new string[] {"emacs",     "emomacocsos"},
            new string[] {"5",         "5"},
            };

        [Test]
        public void TestEnrov()
        {
            string i, o;
            for (int j = 0; j < testPairs.Length; j++)
            {
                i = testPairs[j][0];
                o = testPairs[j][1];
                Assert.IsTrue(rovar.enrov(i) == o, "{0} -> {1} == {2}?", i, o, rovar.enrov(i));
            }
        }
		
        [Test]
        public void TestDerov()
        {
            string i, o;
            for (int j = 0; j < testPairs.Length; j++)
            {
                i = testPairs[j][1];
                o = testPairs[j][0];
                Assert.IsTrue(rovar.derov(i) == o, "{0} -> {1} == {2}?", i, o, rovar.derov(i));
            }
        }
    }
}

Running the tests now till result in broken test (as expected) and something like this:

Implementing enrov and derov

I implement a pretty straight forward enrov and derov, I am sure there are more compact ways of doing it - but since this will later pass the tests I do not have to improve them :)

        public static string enrov(string normal)
        {
            System.Text.StringBuilder builder = new System.Text.StringBuilder();
            
            foreach(char c in normal)
                if (lower_consonants.Contains(c.ToString()))
                    builder.Append(c + "o" + c);
                else if (upper_consonants.Contains(c.ToString()))
                    builder.Append(c + "O" + c);
                else 
                    builder.Append(c);
                            
            return builder.ToString();
        }
        
        public static string derov(string rov)
        {
            foreach(char c in lower_consonants)
                rov = rov.Replace(c + "o" + c, c.ToString());

            foreach(char c in upper_consonants)
                rov = rov.Replace(c + "O" + c, c.ToString());

            return rov;
        }

Analyzing the test results

The Assert.IsTrue(bool b) method has a sibling: Assert.IsTrue(bool b, string s) and we used the latter (there is also a third one with other arguments). Since we used the message it will be a lot easier to find any problems in the tests.

Our error messages was:

By looking at this (even for a few minutes) you should easily notice the missing f in the consonants bug.

If we add the f and rerun the tests it seems to work (at least the tests did not break).

What if I find something the tests do not cover?

If you find something that the tests do not cover - what if we want to do enrov(null) or an empty string? Will the tests cover that?

Whatever you do - make sure you implement the tests first and then implement the functionality you want to test.

Download

Download this solution here: [9]

What about Visual Studio?

From the menu: select Test > New Test > Unit Test. The rest is more or less the same.

http://www.pererikstrandberg.se/blog/dot-net-unit-test/visual-studio-test-driven.png


This page belongs in Kategori Programmering.
This page belongs in Kategori Test
See also Python Unit Test.
See also Sharp Develop.