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.
Showing posts with label polymorphism. Show all posts
Showing posts with label polymorphism. Show all posts
Sunday, September 22, 2013
C#: Mocking and Dependency Injection for Unit Testing a File Sorting Program
Labels:
advanced,
bill gates,
chuck norris,
dependency injection,
files,
inheritance,
interfaces,
io,
linus torvalds,
lists,
mark zuckerberg,
mocking,
nunit,
oop,
polymorphism,
properties,
sharpdevelop,
sorting,
unit testing
Thursday, August 1, 2013
C# OOP: Abstract classes, fruit, and polymorphism
Hello people from around the world!
The previous article, C# OOP: Queues and Stacks with Inheritance, introduced inheritance and showed that it can help you to reuse methods and variables within one class in another class that derives from it. As I explained in that article, when we say "Queue is a List", we mean it in the sense of "Dog is a mammal".
In practice, inheritance relationships can be a little more elaborate than that. Let's take a classic OOP example - shapes:
So we have a Shape, that is the parent to everything else. It defines a GetArea() method which is expected to be defined in each subclass. The area of a square is calculated based on its length, and that of a circle is calculated based on its radius, each area calculation is specific to that particular shape.
Also, we define a rectangle as a special case of a square. That might sound counterintuitive, but in OOP it makes sense. This is because a rectangle requires more specific attributes than a square (i.e. the width). If we did it the other way round, Square would inherit a width attribute that it doesn't really need.
Anyway, as you can see, it doesn't make any sense for you to have an instance of Shape. You can have an instance of Square, or Circle, or Rectangle, and calculate their area. But how would you calculate the area of a Shape? You can't, because a Shape does not exist.
Let me give you a different example: fruit. You have probably seen apples, oranges, bananas, and many other fruit. But have you ever seen something that is a generic fruit? Things like fruit and shapes are called abstract classes: they give you a general idea of what you can do with them, but they can only be subclassed. They cannot be instantiated.
Let's see a fruity example in action. Start a new SharpDevelop C# console application, and start off with the following class:
abstract class Fruit
{
public String name;
public abstract void Eat();
}
Our Fruit has a name, which may be used directly by subclasses. It also declares a method called Eat(), which is abstract. An abstract method is intended to be implemented by subclasses (much like GetArea() in the Shape example), and does not contain any implementation. Abstract methods must be defined in abstract classes, such as Fruit. When a class is abstract, it cannot be instantiated, so trying something like this:
Fruit fruit = new Fruit();
...would cause a compile-time error:
Now, let's add some subclasses to spice things up:
class Apple : Fruit
{
public Apple(String name)
{
this.name = name;
}
public override void Eat()
{
Console.WriteLine("You eat the {0}. Crunch crunch.", this.name);
}
public void Throw(String target)
{
Console.WriteLine("You throw the {0} at the {1}", this.name, target);
}
}
class Orange : Fruit
{
public Orange(String name)
{
this.name = name;
}
public override void Eat()
{
Console.WriteLine("You eat the {0}. Squish squish.", this.name);
}
public void Squeeze()
{
Console.WriteLine("You squeeze the juicy orange into a cup.");
}
}
Each subclass conveniently has a constructor that sets the name variable inherited from the parent (Fruit). Each subclass also implements the Eat() method in its own way. The subclasses must provide an implementation for abstract methods they inherit (a compile-time error occurs if you don't). Finally, the Orange and Apple class each implement a method specific to them: Apple has a Throw() method, and Orange has a Squeeze() method. Note: If you're thinking that oranges can also be thrown, Aladdin would disagree:
You can now create instances of Apple or orange and use them as you like:
Apple apple = new Apple("green apple");
apple.Eat();
apple.Throw("guard");
This gives you the following output:
An Apple is always a Fruit. Although you can't instantiate Fruit directly, you can use an Apple as a Fruit:
Fruit appleFruit = new Apple("green apple");
Since Eat() is originally declared in Fruit, you can call it on a Fruit variable without issues:
appleFruit.Eat();
You can't, however, call Throw() from a Fruit because Throw() is declared in Apple, not in Fruit. Doing this:
apple.Throw("guard");
...results in a compile-time error.
The ability to treat different types of Fruit (Apple, Orange) as if they were Fruit allows you to work with them (using the methods and variables provided by Fruit) without needing to know what subclass they are underneath:
Fruit appleFruit = new Apple("green apple");
Fruit redAppleFruit = new Apple("red apple");
Fruit orangeFruit = new Orange("fresh orange");
List<Fruit> myFruit = new List<Fruit>();
myFruit.Add(appleFruit);
myFruit.Add(redAppleFruit);
myFruit.Add(orangeFruit);
foreach (Fruit fruit in myFruit)
fruit.Eat();
The resulting output is:
This approach is called Polymorphism, and as you can see, it has nothing to do with turning orcs into critters:
A practical example where I've used this is when making games using XNA. You can have many different DrawableGameComponents, each of which may implement its own Draw() method. You can then loop through all your game images (similar to what we did with Fruit) and call Draw() on each of them to draw them on the screen.
Fantastic. In this article we learned about abstract methods, abstract classes, and how to use them polymorphically. An abstract method is a method declaration, without the implementation, that must be implemented in subclasses. Abstract methods are declared in abstract classes, which cannot be instantiated. However, variables of an abstract class type may be used by assigning a subclass. Polymorphism is when we use members of the parent class so that we don't need to distinguish between different subclasses - instead we use the common functionality provided by the parent class.
We've covered quite a bit of ground in OOP, but there is still a lot more to learn: interfaces, overriding, overloading, and, most importantly, encapsulation. Future articles will touch upon these topics as well.
The previous article, C# OOP: Queues and Stacks with Inheritance, introduced inheritance and showed that it can help you to reuse methods and variables within one class in another class that derives from it. As I explained in that article, when we say "Queue is a List", we mean it in the sense of "Dog is a mammal".
In practice, inheritance relationships can be a little more elaborate than that. Let's take a classic OOP example - shapes:
So we have a Shape, that is the parent to everything else. It defines a GetArea() method which is expected to be defined in each subclass. The area of a square is calculated based on its length, and that of a circle is calculated based on its radius, each area calculation is specific to that particular shape.
Also, we define a rectangle as a special case of a square. That might sound counterintuitive, but in OOP it makes sense. This is because a rectangle requires more specific attributes than a square (i.e. the width). If we did it the other way round, Square would inherit a width attribute that it doesn't really need.
Anyway, as you can see, it doesn't make any sense for you to have an instance of Shape. You can have an instance of Square, or Circle, or Rectangle, and calculate their area. But how would you calculate the area of a Shape? You can't, because a Shape does not exist.
Let me give you a different example: fruit. You have probably seen apples, oranges, bananas, and many other fruit. But have you ever seen something that is a generic fruit? Things like fruit and shapes are called abstract classes: they give you a general idea of what you can do with them, but they can only be subclassed. They cannot be instantiated.
Let's see a fruity example in action. Start a new SharpDevelop C# console application, and start off with the following class:
abstract class Fruit
{
public String name;
public abstract void Eat();
}
Our Fruit has a name, which may be used directly by subclasses. It also declares a method called Eat(), which is abstract. An abstract method is intended to be implemented by subclasses (much like GetArea() in the Shape example), and does not contain any implementation. Abstract methods must be defined in abstract classes, such as Fruit. When a class is abstract, it cannot be instantiated, so trying something like this:
Fruit fruit = new Fruit();
...would cause a compile-time error:
Now, let's add some subclasses to spice things up:
class Apple : Fruit
{
public Apple(String name)
{
this.name = name;
}
public override void Eat()
{
Console.WriteLine("You eat the {0}. Crunch crunch.", this.name);
}
public void Throw(String target)
{
Console.WriteLine("You throw the {0} at the {1}", this.name, target);
}
}
class Orange : Fruit
{
public Orange(String name)
{
this.name = name;
}
public override void Eat()
{
Console.WriteLine("You eat the {0}. Squish squish.", this.name);
}
public void Squeeze()
{
Console.WriteLine("You squeeze the juicy orange into a cup.");
}
}
Each subclass conveniently has a constructor that sets the name variable inherited from the parent (Fruit). Each subclass also implements the Eat() method in its own way. The subclasses must provide an implementation for abstract methods they inherit (a compile-time error occurs if you don't). Finally, the Orange and Apple class each implement a method specific to them: Apple has a Throw() method, and Orange has a Squeeze() method. Note: If you're thinking that oranges can also be thrown, Aladdin would disagree:
You can now create instances of Apple or orange and use them as you like:
Apple apple = new Apple("green apple");
apple.Eat();
apple.Throw("guard");
This gives you the following output:
An Apple is always a Fruit. Although you can't instantiate Fruit directly, you can use an Apple as a Fruit:
Fruit appleFruit = new Apple("green apple");
Since Eat() is originally declared in Fruit, you can call it on a Fruit variable without issues:
appleFruit.Eat();
You can't, however, call Throw() from a Fruit because Throw() is declared in Apple, not in Fruit. Doing this:
apple.Throw("guard");
...results in a compile-time error.
The ability to treat different types of Fruit (Apple, Orange) as if they were Fruit allows you to work with them (using the methods and variables provided by Fruit) without needing to know what subclass they are underneath:
Fruit appleFruit = new Apple("green apple");
Fruit redAppleFruit = new Apple("red apple");
Fruit orangeFruit = new Orange("fresh orange");
List<Fruit> myFruit = new List<Fruit>();
myFruit.Add(appleFruit);
myFruit.Add(redAppleFruit);
myFruit.Add(orangeFruit);
foreach (Fruit fruit in myFruit)
fruit.Eat();
The resulting output is:
This approach is called Polymorphism, and as you can see, it has nothing to do with turning orcs into critters:
A practical example where I've used this is when making games using XNA. You can have many different DrawableGameComponents, each of which may implement its own Draw() method. You can then loop through all your game images (similar to what we did with Fruit) and call Draw() on each of them to draw them on the screen.
Fantastic. In this article we learned about abstract methods, abstract classes, and how to use them polymorphically. An abstract method is a method declaration, without the implementation, that must be implemented in subclasses. Abstract methods are declared in abstract classes, which cannot be instantiated. However, variables of an abstract class type may be used by assigning a subclass. Polymorphism is when we use members of the parent class so that we don't need to distinguish between different subclasses - instead we use the common functionality provided by the parent class.
We've covered quite a bit of ground in OOP, but there is still a lot more to learn: interfaces, overriding, overloading, and, most importantly, encapsulation. Future articles will touch upon these topics as well.
Subscribe to:
Posts (Atom)