Gigi Labs

Please follow Gigi Labs for the latest articles.
Showing posts with label unit testing. Show all posts
Showing posts with label unit testing. Show all posts

Wednesday, October 30, 2013

C#: Unit Testing for Old or Express Visual Studio Editions Using NUnit

Hello folks! :)

I've written a few articles about unit testing so far. If you can use NUnit from within SharpDevelop, or use MSTest directly from within Visual Studio 2010+, then you are probably writing and running unit tests pretty comfortably.

Unfortunately, however, such luxury is not always available. Express editions of Visual Studio do not have the inbuilt MSTest features that the paid editions have; and older editions of Visual Studio did not have any unit testing functionality whatsoever. Fortunately, however, NUnit provides tools that can run unit test projects anyway. To show how this works, I'm going to demonstrate how to run unit tests for a project created in Visual Studio 2005.

The first thing we need is to download NUnit and then install it.


As we've already seen in "C#: Unit Testing with SharpDevelop and NUnit", this gives us the nunit.framework.dll file which we will need to reference in order to create our test project. You can find it in the bin\framework folder relative to wherever you installed NUnit:


Next, let's create our project via the File menu -> New -> Project... and then select Console Application and decide what to name your project and where to place it:


Make the Program class public so that our test project will be able to see it:

    public class Program

Then add the following method which we will be testing:

        public static String Shorten(String input)
        {
            if (input.Length > 20)
                return input.Substring(0, 18) + "...";
            else
                return input;
        }

This method shortens a piece of text that is longer than a specified length (in this case 20 characters) - it truncates the string and adds "..." to show that there's more to it. This is sometimes useful when you need to fit text in a fixed width, such as on an internet forum.

Now, let's write some tests. The first thing we need to do is create our test project. And since we don't have the luxury of Unit Test Projects like we saw towards the end of "Unit Tests, The Visual Studio Way", we'll make a Class Library instead. A class library is a project that results in a .dll file that you can deploy with your executable - it's great for splitting up more complex projects. You can put your classes and other stuff in a .dll, and other projects can use them as long as they're public (that's why we made the Program class public).

Right click on the solution and go Add -> New Project... . Select "Class Library" as the project type, name it CsNUnitExternal.Tests, and hit OK.

Right click the new project, select "Add Reference..." (which might seemingly hang older versions of Visual Studio, but just be patient until it becomes responsive again), select the Browse tab, and locate the bin\framework\nunit.framework.dll file from your NUnit installation.

Add another reference, this time via the Projects tab, to the original project where your code is.

Delete the Class1.cs file that's created by default, and add a new class instead (right click on the new project, Add -> Class...), called ProgramTests. Near the top, add the following line so that we can use NUnit's functionality:

using NUnit.Framework;

Just beneath it, add the following, so that we can use the Program class and its Shorten method from our original project:

using CsNUnitExternal;

Add the TestFixture attribute on top of the class name so that NUnit can recognise it:

    [TestFixture]
    class ProgramTests

Finally, add a couple of tests as follows:

    [TestFixture]
    class ProgramTests
    {
        [Test]
        void Shorten_LongString_Shortened()
        {
            String input = "In the jungle the mighty jungle the lion sleeps tonight";
            String expected = "In the jungle the ...";
            String actual = Program.Shorten(input);
            Assert.AreEqual(expected, actual);
        }

        [Test]
        void Shorten_ShortString_Shortened()
        {
            String input = "Midnight Special";
            String expected = "Midnight Special";
            String actual = Program.Shorten(input);
            Assert.AreEqual(expected, actual);
        }

This is what it looks like with colour and all - pretty enough to be placed inside a museum:


OK, now how do we run these tests? Conveniently, NUnit has this unit test runner program that we can use. You can get to it either from the bin folder in the NUnit installation, or via the Start menu (or whatever your Windows edition has instead).


Build your projects by pressing either F6 or Ctrl+Shift+B. Then, find your CsNUnitExternal.dll file in the relevant project's bin\Debug folder, and drag it onto the left part of the NUnit window (or load it via the File menu). The test class and relevant tests are loaded:


Running the tests now (Run button) will cause them to fail, and NUnit shows a big red bar as well as the reasons why the tests failed:


As the error messages indicate, we need to change our test class and methods to public, build the project again (at which point NUnit automatically reloads them), and then rerun the tests. We've gone green! :)

Sweet. In this article, we saw how we can use NUnit to run unit tests even when we have no in-built support for them from the IDE, such as old versions of Visual Studio (2008 and earlier), or Express editions of Visual Studio. We can do this by creating our tests in a class library, and then loading and running the tests in NUnit's own test runner, which is an external tool.

I hope you found this retro experience useful. Stay tuned for more articles coming soon! :)

Monday, October 28, 2013

Unit Tests, The Visual Studio Way

Hi! :)

Last month I wrote a couple of articles on unit testing: "C#: Unit Testing with SharpDevelop and NUnit" and "C#: Mocking and Dependency Injection for Unit Testing a File Sorting Program". These articles gave an introduction to unit testing using SharpDevelop and NUnit. If you're a Visual Studio user, however, you might prefer to use Visual Studio's own unit testing framework, known as MSTest. Visual Studio makes it really easy to run and debug tests directly from within the IDE, however writing the tests is slightly different.

In order to follow along, you'll need a version of Visual Studio from 2010 onwards, and one that includes unit testing (that doesn't include the Express editions, sorry). To demonstrate how to to write unit tests in Visual Studio, we're going to write a little program that tells us whether a year is a leap year or not.

First, let's create a new Console Application in Visual Studio 2010. You can do this by clicking on the "New Project..." link on the Start Page, or through the File Menu.


Above your Main() method, add a public static method called IsLeapYear():

        public static bool IsLeapYear(int year)
        {
            return false; // TODO
        }

We can now implement the logic that will decide whether the year is a leap year or not. We can use the leap year algorithm on Wikipedia. The leap year calculation, although not quite complex, might seem oddly contrived if you're looking at it for the first time. If you're curious about why there are so many conditions, you might want to check out this question on StackOverflow.

So the method ends up looking like this:

        public static bool IsLeapYear(int year)
        {
            if (year % 400 == 0)
                return true;
            else if (year % 100 == 0)
                return false;
            else if (year % 4 == 0)
                return true;
            else
                return false;
        }

The % is called a modulus operator - it performs a division but returns the remainder, not the result. So you know that year is divisible by 4 because the remainder is zero.

Right, now let's create some unit tests for our shiny new method. Before you run off and start belching out code, Visual Studio has this really neat feature where you can just right click somewhere empty and select "Create Unit Tests...":



In the screen that pops up, you can select the methods and properties for which you want to create unit tests. In our case it's just one method, but this is really useful if you have lots of code and want to generate a bunch of skeleton unit tests quickly.


In the "Output project" option at the bottom, you can choose whether to create a new test project or use an existing one. Again, in our case we can just create a new one, but if you already have a test project and want to add to it, you can just select it from the drop-down list. Anyway, hit "OK", name your unit tests project, and hit "Create". By convention, tests projects are usually named as [ProjectName].Tests .


Now, when you're done, you might get this message about InternalsVisibleTo:


See, this is because our Program class is not public, and that makes it internal by default. This means that the test project can't see it. Visual Studio allows projects to access non-public classes anyway by using this thing called InternalsVisibleTo, but in most cases I wouldn't recommend it. Just hit "No".

So now Visual Studio created a new project and some code for us:


In the test project, you'll notice that there's a reference to our LeapYearVs2010 project (because the tests need to use our actual code), and there's also a reference to this Microsoft.VisualStudio.QualityTools.UnitTestFramework thing (try fitting that in a business card) - that's needed for unit tests projects.

You'll also notice a bunch of code was generated. It's mostly full of crap, so let's just take out the bull and leave the beef:

using LeapYearVs2010;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace LeapYearVs2010.Tests
{
    [TestClass()]
    public class ProgramTest
    {
        [TestMethod()]
        [DeploymentItem("LeapYearVs2010.exe")]
        public void IsLeapYearTest()
        {
            int year = 0; // TODO: Initialize to an appropriate value
            bool expected = false; // TODO: Initialize to an appropriate value
            bool actual;
            actual = Program_Accessor.IsLeapYear(year);
            Assert.AreEqual(expected, actual);
            Assert.Inconclusive("Verify the correctness of this test method.");
        }
    }
}

So, our usings include our LeapYearVs2010 project, and also a namespace for MSTest unit testing. Other than that, it's pretty straightforward: you have a test class (aptly marked with the [TestClass()] attribute, and it contains one or more unit tests (marked with the [TestMethod()] attribute). I know we haven't quite talked about attributes so far, but just stick them in the right places and don't worry about them.

Before we can write any proper unit test code, we'll need to make our Program class (in the LeapYearVs2010 project) public:

    public class Program

We can now write our first unit test. At times you might find the autogenerated skeleton code for unit tests useful, but in our case you can just throw it out and replace it with this:

        [TestMethod()]
        public void IsLeapYearTest()
        {
            int year = 2001;
            bool expected = false;
            bool actual = Program.IsLeapYear(year);
            Assert.AreEqual(expected, actual, "2001 shouldn't be a leap year!");
        }


You can now run the unit tests via the Test menu, -> Run -> All Tests in Solution, or else by right clicking on a TestClass or TestMethod and selecting "Run Tests". This right click option is context sensitive, so if you Run Tests on a TestMethod it will run that unit test; if you Run Tests on a TestClass it will run all unit tests for that class.

Right, now at this point, if you also have Visual Studio 2012 installed, you might run into this bug where the tests will just kinda get stuck, like this:


Apparently this is a known issue and you'll need to install Service Pack 1 for Visual Studio 2010 to get things working. When they do, you'll see a nice green tick mark next to your test:


Let us now add another test:

        [TestMethod()]
        public void IsLeapYearTest2()
        {
            int year = 1900;
            bool expected = true;
            bool actual = Program.IsLeapYear(year);
            Assert.AreEqual(expected, actual);
        }

Run it as before, and...


Whoops! Our second test failed. You can right click the test in the Test Results window and select "View Test Results Details" to obtain additional information including a stack trace (see screenshot above). If you need to, you can put a breakpoint in your test and then from the Test menu go to Debug -> Tests in Current Context while your cursor is in the unit test you want to debug. You can then debug the test as you would with normal code.

In our case, it's pretty clear that 1900 can't be a leap year because it's divisible by 100 but not by 400. So we need only update the expected value as follows:

            bool expected = false;

Finally, let's take a look at how to create unit tests in Visual Studio 2012 and 2013. I'm going to create a new Console Application in this dark-themed VS2013 which looks like it came out of a chimney:


I'm going to set up Program just as I did in VS2010: make the class public, and add the method as before:

        public static bool IsLeapYear(int year)
        {
            if (year % 400 == 0)
                return true;
            else if (year % 100 == 0)
                return false;
            else if (year % 4 == 0)
                return true;
            else
                return false;
        }

Now, let's create the unit tests. Right click in some empty space and...


Uhhhh... crap. Apparently the "Create Unit Tests..." option was removed in Visual Studio 2012, much to people's frustration. Fortunately, there are workarounds that can bring it back. If you don't want to do those, however, you're just going to have to create the test project and unit tests manually. To do this, right click on the solution, then Add -> New Project..., and from the Test category on the left, select "Unit Test Project". Give it a name and hit "OK".


This generates empty test code, and you can take off writing your unit tests from here. With VS2012, it's the same procedure.


Wow, this was long. Well, I hope it helped you learn about some of the unit testing tools that Visual Studio has to offer. It's very convenient because you can run and debug tests directly from within Visual Studio, and in Visual Studio 2010 there is the "Create Unit Tests" option which can be used to quickly generate skeleton code for unit tests of existing code. Sadly, this option is no longer there by default as from Visual Studio 2012, but there are ways of getting it back.

Check back for more programming goodness at Programmer's Ranch! :)

Sunday, September 22, 2013

C#: Mocking and Dependency Injection for Unit Testing a File Sorting Program

Hullo folks! :)

In yesterday's article, "C#: Unit Testing with SharpDevelop and NUnit", we learned about unit tests: what they are, why we use them, and how we write and execute them. The article ended with a number of insights about them. One of these insights was that it is not easy to write unit tests for code that relies on databases, the network, or other external resources.

In today's article, we're going to address this problem by learning about mocking and dependency injection. These might sound like big buzz-words, but you'll see in this article that they're really nothing special. To see this in action, we'll write a small program that loads a file from the hard disk and sorts it alphabetically, line by line.

This article is a bit on the advanced side, so ideally you should know your OOP and also be familiar with basic unit testing (e.g. from yesterday's article) before reading it.

Start off by creating a new Console Application in SharpDevelop. When this is done, add a new class (right click on project in Projects window, Add -> New Item...) and name it Sorter. At the top, add the following to allow us to read files and use lists:

using System.Collections.Generic;
using System.IO;

Next, add a member variable in which we can store the lines in the file:

private String[] lines;

Add a constructor in Sorter that takes the name of the file to sort, and loads it into the variable we just declared:

        public Sorter(String filename)
        {
            this.lines = File.ReadAllLines(filename);
        }

Now, add a method that actually does the sorting:

        public String[] GetSortedLines()
        {
            List<String> sortedLines = new List<String>(lines);
            sortedLines.Sort();
            return sortedLines.ToArray();
        }

This way of sorting is not the only one and not necessarily the best, but I chose it because it's simple and doesn't change the lines variable, just in case you want to keep it in its original unsorted format for whatever reason.

Let's try and write a test for this code. Add a new class called SorterTest (as I've already mentioned in yesterday's article, people usually put tests into their own project, but I'm trying to teach one concept at a time here). After adding a reference to nunit.framework.dll (check yesterday's article in case you're lost), set up the SorterTest.cs file as follows:

        [Test]
        public void GetSortedLinesTest()
        {
            Sorter sorter = new Sorter("test.txt");
            String[] s = sorter.GetSortedLines();
          
            Assert.AreEqual("Gates, Bill", s[0]);
            Assert.AreEqual("Norris, Chuck", s[1]);
            Assert.AreEqual("Torvalds, Linus", s[2]);
            Assert.AreEqual("Zuckerberg, Mark", s[3]);
        }

Create a file in your bin\Debug folder called test.txt and put the following in it:

Zuckerberg, Mark
Norris, Chuck
Gates, Bill
Torvalds, Linus

Open the Unit Tests window in SharpDevelop (View -> Tools -> Unit Tests) and run it. You can see that the test passes.

Great.

Actually, this is the wrong way of writing unit tests for this kind of thing. We have a dependency on the filesystem. What would happen if that file suddenly disappears? As a matter of fact, we are supposed to be testing the sorting logic, not whether the file is available or not.

In order to do this properly, we're going to have to refactor our code. We need to take our file loading code out of there. Create a new class called FileLoader and add the following at the top:

using System.IO;

...and then set up FileLoader as follows:

    public class FileLoader
    {
        private String[] lines;
      
        public String[] Lines
        {
            get
            {
                return this.lines;
            }
        }
      
        public FileLoader(String filename)
        {
            this.lines = File.ReadAllLines(filename);
        }
    }

In Sorter, remove the constructor as well as the using System.IO; and the lines variable. Instead, we'll pass our FileLoader as a parameter:

        public String[] GetSortedLines(FileLoader loader)
        {
            List<String> sortedLines = new List<String>(loader.Lines);
            sortedLines.Sort();
            return sortedLines.ToArray();
        }

This is called dependency injection: instead of creating the dependency (in our case a file) from within the Sorter class, we pass it as a parameter. This allows us to substitute the dependency for a fake (known as a mock). To do this, we'll need to take advantage of polymorphism (see "C# OOP: Abstract classes, fruit, and polymorphism". Create an interface (when adding a new item, instead of Class, specify Interface) and name it IFileLoader:


An interface is a form of abstract class - it cannot be instantiated, and it declares methods and/or properties that don't have any implementation because they should be implemented by the classes that inherit from (or implement) that interface. In an interface, however, no methods/properties have an implementation. It is used as a contract, saying that any class implementing the interface must implement its methods/properties. In our case, IFileLoader will be this:

    public interface IFileLoader
    {
        String[] Lines
        {
            get;
        }
    }

We then specify that FileLoader implements IFileLoader; this is the same as saying that FileLoader inherits from IFileLoader:

public class FileLoader : IFileLoader

FileLoader already has the necessary Lines property, so we're fine. Next, we replace the FileLoader parameter in Sorter.GetSortedLines() with an instance of the interface:

public String[] GetSortedLines(IFileLoader loader)

This allows us to pass, as a parameter, any class that implements IFileLoader. So we can create a class, MockFileLoader, that provides a hardcoded list of names:

    public class MockFileLoader : IFileLoader
    {
        private String[] lines = { "Zuckerberg, Mark""Norris, Chuck""Gates, Bill""Torvalds, Linus" };
      
        public String[] Lines
        {
            get
            {
                return this.lines;
            }
        }
    }

We can now rewrite our unit test like this:

        [Test]
        public void GetSortedLinesTest()
        {
            IFileLoader loader = new MockFileLoader();
            Sorter sorter = new Sorter();
            String[] s = sorter.GetSortedLines(loader);
          
            Assert.AreEqual("Gates, Bill", s[0]);
            Assert.AreEqual("Norris, Chuck", s[1]);
            Assert.AreEqual("Torvalds, Linus", s[2]);
            Assert.AreEqual("Zuckerberg, Mark", s[3]);
        }

If you run the unit test, you'll find that it works just like before, just that this time our unit test isn't dependent on any file and can run just file without one:


In this article, we have seen how to create mock classes that emulate the functionality of our normal classes, but can replace them in unit tests when dependencies exist. To facilitate this, both the mock class and the normal class implement a common interface, and an instance of this interface is passed as a parameter to the method being tested. This is called dependency injection and allows us to control what is being passed to the method.

It is not always easy to write mocks. First, as this article has shown, code may need to be refactored in order to isolate dependencies and support dependency injection. Secondly, mocking complex classes (e.g. an IMAP server) can take a great deal of effort and might not necessarily be worth it. Use your own judgement to decide whether you need unit tests in such situations.

Thanks for reading, and be sure to visit here often to read more articles that might be useful.

Saturday, September 21, 2013

C#: Unit Testing with SharpDevelop and NUnit

Hey there! :)

In today's article I'm going to introduce unit testing, and show how basic unit tests can be written and run from within SharpDevelop. This is just one way of doing unit testing; Visual Studio's integrated unit testing suite is a pretty good alternative, or else you could use NUnit separately from your IDE; but let's not go there at this stage.

As usual, let's avoid lengthy overviews and learn about unit testing by doing it. To start off, create a new SharpDevelop project. Then, right click on the project in Solution Explorer and select Add -> New Item...; from there, add a new class called EmailAddress:


Set up the class such that it can be used to store an email address provided in its constructor:

    public class EmailAddress
    {
        private String emailAddress;
      
        public EmailAddress(String emailAddress)
        {
            this.emailAddress = emailAddress;
        }
    }

In the EmailAddress class, add a simple method to check whether the email address it contains is a valid one:

        public bool IsValid()
        {
            if (this.emailAddress.Contains("@"))
                return true;
            else
                return false;
        }

Let's add also add some code in Main() that will allow us to test this manually:

         public static void Main(string[] args)
        {
            Console.WriteLine("Enter your email address: ");
            String emailStr = Console.ReadLine();
            EmailAddress emailAddress = new EmailAddress(emailStr);
          
            if (emailAddress.IsValid())
                Console.WriteLine("Congratulations, your email is valid!");
            else
                Console.WriteLine("Oops, that's not a valid email address!");
          
            Console.ReadKey(true);
        }

Now, we could run the program several times, each time giving it a different email address to test it, but this would be tedious. Instead, we can write unit tests. These are normally kept in a separate project, but to keep things simple, we'll use the same project. Before we proceed, though, you'll need to download and install NUnit. When you're done, you should be able to find nunit.framework.dll in NUnit's bin\framework folder:


Back in SharpDevelop, from Solution Explorer, right click on the project and select Add Reference...:


In the window that appears, select the ".NET Assembly Browser" tab, hit the "Browse..." button, and locate the nunit.framework.dll file as above. This will allow you to use NUnit's functionality directly from within SharpDevelop.

Add a new class called EmailAddressTest and replace the default contents of the file with the following code:

using System;
using NUnit.Framework;

namespace CsSdUnitTesting
{
    [TestFixture]
    public class EmailAddressTest
    {
        [Test]
        public void EmailAddressTest_Simple_Valid()
        {
            EmailAddress email = new EmailAddress("test@example.com");
            bool isValid = email.IsValid();
            Assert.IsTrue(isValid);
        }
    }
}

Note how, on the second line, we are using the NUnit.Framework namespace, which comes from the nunit.framework.dll to which we have just added a reference. This allows us to mark classes containing tests with the TestFixture attribute, and test methods with the Test attribute.

The method you see above is an example of a unit test: in it, we create an instance of our EmailAddress class, and test a particular method (in this case the IsValid() method). We hardcode an input, evaluate the method, and define an expected output using one of the many methods in the Assert class.

Let's actually run this unit test. Open the Unit Tests window by going to the View menu and then selecting Tools -> Unit Tests:


Once the Unit Tests window opens up on the right, you can just hit one of the Play buttons to run your tests:


Your unit tests should capture not only valid data, but also cases that are meant to fail. For example, this unit test catches invalid email addresses that are missing the '@' character:

        [Test]
        public void EmailAddressTest_NoAt_Invalid()
        {
            EmailAddress email = new EmailAddress("hello");
            bool isValid = email.IsValid();
            Assert.IsFalse(isValid);
        }

When you run this test, you should get a green light just as before, showing that the test has passed.

Now, let's try a different test:

        [Test]
        public void EmailAddressTest_NoDomain_Invalid()
        {
            EmailAddress email = new EmailAddress("test@");
            bool isValid = email.IsValid();
            Assert.IsFalse(isValid);
        }

This test is supposed to catch cases where there is no domain, and we expect it to be invalid. So we run the tests again:


Crap. Our test failed, so we need to go back and fix the code. When logic is complicated, you can set breakpoints in the tests and run the tests within the debugger, saving you from having to actually run the program itself (which may take time for more complex applications).

There are many ways to verify an email address, including using the MailAddress class or using a regular expression. In my case I wrote a simple regular expression which does not cover every case but is enough for what we need. I haven't covered regular expressions, but don't worry, just use this code for IsValid():

        public bool IsValid()
        {
            if (Regex.IsMatch(emailAddress, @"\w+\@\w+(\.\w+)+"))
                return true;
            else
                return false;
        }

You will also need to put this at the top for it to work:

using System.Text.RegularExpressions;

If you run the tests now, they should all pass. If someone happens to change the regular expression in the future and breaks something, re-running the tests should allow you to detect the issue. Re-running a test to see whether something broke is called a regression test, and is a great way to detect problems early and fix them before they make it into a release.

In this article you have seen how unit tests are used, with the example of validating an email address. There is a lot more to say about unit tests, but this should suffice as an introduction. I will mention a few points however:
  • Unit tests allow you to test a single unit of functionality, often a method or property.
  • As such, they work great with methods that have a clear input and output (such as a method which takes an email address in String format and returns a boolean indicating whether it is valid or not).
  • Unit tests are not easy to write for methods which are not public, which are void, or which do not take parameters. In Visual Studio there is a way to get around this, but in NUnit you have to refactor your code.
  • Unit tests are really tricky to write for methods which rely on external resources such as files, databases, or remote network locations. To make them work in such scenarios, techniques such as dependency injection and mocking come into play.
  • Unit tests won't make your code bug-free, especially if you don't write unit tests to handle the majority of possible inputs. They won't solve all your problems, so use them only when they are worth the effort.
  • Some people like to write unit tests before the actual development code - this is called Test Driven Development (TDD).
That's all, folks! Stick around, as articles are posted here regularly. :)