Time-Tested Testing Tips - Part 1

These days more and more people seem to be testing. I admit I am one of the developers who has been writing unit, integration, acceptance, regression, and other tests. The idea of testing has been around for a long time, but it seems lately there has been a surge of people beginning to use them. Some are having great success and some are seeing their success fall away. Simply writing tests does not suddenly make great code.

Something I think everyone should know is that testing code is desired because it allows us a few benefits; the confidence that everything is working, the confidence that a bug has been eliminated, ease of maintainability, and extra documentation of a system written in code.

Tests as Documentation

I believe I've said plenty of times in the past that the tests you write become excellent documentation which can be used to demonstrate how different aspects of your system should be used. This is very useful for someone joining a project. If it is well-documented in its tests, learning how to work with the code is as easy as reading through the tests and seeing how the different objects are intended to interact. If you can't do this, you're probably not testing well.

A good measure of your application's testing is to have someone learn to use the system based solely on the tests. If the tests are written well enough, someone will be able to figure out how everything works and interacts.

This is one of my primary goals when testing an application. I want to make sure that things are clear, because when I come back to this code a month from now I will be that new developer on the project. I will need to know how to use the classes, interfaces, etc. and having it documented in working cases goes a long way.

How many tests should I write?

This is one of the most common questions asked by new testers. For now I will take the cowardly approach and say, "it depends". I've read posts from people touting the number of tests they've written. This is a new metric as if "line count" wasn't already bad enough. There is a balance here that we are looking for. Just with the line count.

If your line count is small you're application probably doesn't do very much and if it is large then your application might be cumbersome and difficult to maintain. When you don't have many tests your code is more prone to errors, but if you've written too many tests maintainability disappears. But wait! Didn't I say earlier that tests make code more maintainable. Well, yes I did, but if you write too many it becomes difficult to change the code. If you test every single possible minute little thing in your application you're going to have a heck of a time changing anything.

When you're writing tests make sure you have just enough to give yourself confidence that your code is working.

I highly recommend against ever setting code coverage or test count goals. If you set goals for these you're just creating incentives to write more tests than is required. Too many tests can create the same problems as too much code. Why? Because tests are code.

You need to treat your test code well. It needs to follow a lot of the same rules as the rest of what you write.

LINQ Your Collections with IEqualityComparer and Lambda Expressions

Anyone using LINQ to manipulate in-memory collections is probably also using plenty of lambda expressions to make things quite easy. These two additions were really meant for each other. One of our interns here recently ran into an interesting problem while using LINQ. As a relatively new user of .NET based languages, reference types caused him a bit of trouble.

The problem

While using the dot notation with lambda expressions, he was using the Except method in the following way.

List<MyObject> x = myCollection.Except(otherCollection).ToList();

Well the problem here is that these two collections contain "MyObject"s, and when it does the comparison it does so based on the reference. This means if those are separate but equivalent objects that the comparison will claim they are different.

He had unit tests making sure that the except statement worked, but was using the same instance of variables to Assert, so the tests claimed to work.

I told him the problem and mentioned that there was probably an overload of Except that allows one to specify how to do the comparison. I was correct, but the overload takes an IEqualityComparer object. I was hoping for a Func<x,x,bool> as the second parameter, so I did what I always do; I Googled to see if anyone knew an easy way to get that to work without doing extra work.

The Internet was kind enough to inform me that there was no built in way of handling this situation.

Building your own was the suggestion. It is a pretty simple class, so it can just be tossed somewhere to be reused easily. It could easily come up and be needed again.

public class LambdaComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, T, bool> _lambdaComparer;
    private readonly Func<T, int> _lambdaHash;

    public LambdaComparer(Func<T, T, bool> lambdaComparer) :
        this(lambdaComparer, o => 0)
    {
    }
    
    public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
    {
        if (lambdaComparer == null)
            throw new ArgumentNullException("lambdaComparer");
        if (lambdaHash == null)
            throw new ArgumentNullException("lambdaHash");

        _lambdaComparer = lambdaComparer;
        _lambdaHash = lambdaHash;
    }

    public bool Equals(T x, T y)
    {
        return _lambdaComparer(x, y);
    }

    public int GetHashCode(T obj)
    {
        return _lambdaHash(obj);
    }
}

Now that we have a nice, Generic, comparer which can take lambda expressions, we are all set to plug this in to the previous code.

List<MyObject> x = myCollection.Except(otherCollection, 
  new LambdaComparer<MyObject>((x, y) => x.Id == y.Id)).ToList();

// or

IEqualityComparer comparer = new LambdaComparer<MyObject>((x, y) => x.Id == y.Id);
List<MyObject> x = myCollection.Except(otherCollection, comparer).ToList();

I admit I am still kind of annoyed that there wasn't an overload which just took a Func<T, T, bool> or a Func<T, T, int>.

Either way, I hope this helps someone use LINQ a little more easily. I know of some alternate ways of solving this same problem. So if you think I should have solved this differently then blog it and link back here or just post a comment below.

Update 16 April 2009 - From a comment below

One commenter below posted a suggested extension method for use with this. He suggests using this nice extension method so you can hide away the fact that you're using the custom comparer class.

public static class Ext
{
    public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, 
        IEnumerable<TSource> second , Func<TSource, TSource, bool> comparer )
    {
        return first.Except(second, new LambdaComparer<TSource>(comparer));
    }
}

Thank you for the comment. I like the idea. It will very nicely hide away the fact that a silly comparer is needed.

We Slice Software Vertically Just Like Bread

Bread When working on a feature or some other aspect of a software project, it is important to figure out what piece you want to do at any given time. There are two primary routes you could take. Perhaps you want to go and create the whole UI, but have nothing wired up. Maybe you want to go and write all the business logic first, and you might want to go create the data layer and underlying infrastructure. If you do one of those then I will call you crazy.

I believe in vertically slicing an application. You never know at the beginning of a project what scope creep is going to occur, and you also don't know which aspects of your initial design will be completely unnecessary. One of the main reasons why so many people are against "big design up front" is because we don't know what we're going to need in the end.

If we're working in vertical slices, we can complete an entire piece of functionality that we know we need. This is why we work with vertical slices. We can stop at any time, and there are no unused pieces. Everything we've completed is there and working.

If we ignore how references in our application might be set up and just look at the structure of an application with a very simplistic view, we might say that there is a UI that calls some form of business logic which in some way talks to some kind of data.

Basic Structure of a Project

ThreeLayers

Say for example that we are going to work with a horizontal slice. Yes, plenty of people do this. I tried working on an application this way many years ago. So perhaps we are thinking, "hey, why don't we get the database and the data layer hashed out at the beginning then we can just write all the code on top of it later." After working on this for a while we might end up with something like this. The blue is the completed work.

Work Done Horizontally

HorizontalWork

Now for some questions.

  • How much can we show the customer? Nothing.
  • Are we sure we structured everything the way the customer wanted? No.
  • What if this is an open source project, maybe we want to encourage other developers to join the project. Are these developers able to see the structure of our application and how we want things to work? Well it looks like.... no.

Now what if we had done the same amount of work vertically? We might end up with something like this.

Work Done Vertically

VerticalWork

Now assume that this is the same amount of work as if we had worked horizontally. Sure we have a lot less breadth, but the depth of our work is far greater. Now if we ask those same questions.

  • How much can we show the customer? Everything we've worked on.
  • Are we sure we structured everything the way the customer wanted? Yes, because the customer can see it and can tell us right now if we did something wrong. We are able to quickly respond to and fix the problem.
  • What if this is an open source project, maybe we want to encourage other developers to join the project. Are these developers able to see the structure of our application and how we want things to work? They can see everything we've done. Anyone hopping on this project would see the full structure and know how the layers are interrelated and would likely be able to add meaningful work to the project.

My Past Horizontal Mistake

So I mentioned early in this article that I tried horizontally working on a project once.  Yeah, that was a mistake. As you get to new aspects of a project a little thing called scope creep occurs. As you get to and think about new pieces of an application you realize new ways you can improve them, right? Well, this is another major problem with working horizontally. As I added new pieces, I came up with new stuff I wanted to do. New ways of doing things came to mind. Eventually I had scope creeped the data enough that I ended up giving up on the project.

I've recently started working on the project again, but this time I am of course working with vertical slices. I am going to make pieces just large enough to give me some value. That way at any point I could stop development and have a working tool. One which does something. Maybe not everything I want, but enough.

A Skill to Learn

Breaking tasks into thin vertical slices is difficult. Without advances in bread slicing technology, the processed, sliced bread from stores could never be so thin. It isn't easy to make thin slices, but the thinner the slice the better we are able to get the amount of bread we want. Perhaps we want 3 slices. Before we had these thin slices it might have been one and a half, but the thin slices make everything easier.

Some tasks look like they'll take weeks to complete. That my friend is not a task. We need to split that. There is probably some aspect of that which could be completed in a day. Maybe it wouldn't be in a shippable state, but there would be something that the customer could see. An initial bit working that is not the whole thing. This gives us two things. It shows the customer what we're working on, and it also gives them the chance to give us feedback. We can more easy adjust that small slice than if we had delivered the whole feature at once.

A Slicing Example

Assume we have a web site. We want to add user profiles to the site. Our customer comes along and says he wants the profile to have this information.

  • Full Name
  • Nickname
  • Location
  • Age
  • Gender
  • List of current and previous occupations
  • List of educational institutions
  • List of favorite games
  • List of favorite movies
  • List of favorite books
  • List of favorite songs
  • List of favorite musicians
  • List of favorite places
  • List of friends

If you went to do all of this at once it could take you a while. This is a good time to figure out some nice places to split things. An obvious split here is to do everything that is not complicated. For this we could say the top 5 ones we'll do. These don't have lists.

Slice 1: Create Full Name, Nickname, Location, Age, and Gender as a profile and create a view and edit page for them.

That slice is very manageable, and when you're done you can show the customer and make sure that is what they were expecting. Perhaps they wanted Full Name to be 3 separate pieces: First, Middle, and Last. Since we haven't done much, this is easy to change right now.

Now we might say that the next slice is the next item on the list. Why? Because we want to get one of the lists in place and the functionality set up and to the customer for feedback.

Slice 2: Add a list of current and previous occupations to the user profile.

Ok so we implement this basically as a list of strings. The user puts in the name of the occupation and adds more in the same way. We display this list of occupations on the profile page. Now when we show the customer this he says that he wants the list to intelligently suggest occupation names as the user types with previously used occupations. So now it is a bit more complicated, but we make the change. We then ask if the same will be done with the other lists, and the customer says "yes". Now we know how to do these next ones.

As we work through the next few slices, maybe the customer decides that we don't need both musicians and songs. The customer gets rid of musicians. Well we benefit here, because we hadn't put any work into that yet.

I really want to emphasize here that a slice should be small. Vertical slices are there so you always have a working product. At any moment you could stop. Maybe we stopped before doing the lists of things. We had a working solution at that moment. The other big reason we do vertical slices is so people can se what we've done and give us feedback. Customers might give you feedback on the UI, but until it is wired up and working the feedback isn't as useful.

Just In Time Properties

Properties with backing fields can easily be null. I often see properties which check the backing field to see if it is null. This is commonly done with an if statement with one line of initialization. One way to get around this is to use the coalescing operator in C#. If we use this in combination with an expressions, which might be a method, we are able to easily handle this property with one line.

Here is an example of what I am talking about.

private SomeType _someObject;
public SomeType SomeObject 
{ 
    get 
    { 
        return _someObject ?? (_someObject = giveMeSomeObject()); 
    } 
}

Notice how short and concise this is. I am able to with one line which is very clear handle this common scenario. Sure it doesn't always match this exactly, but I see plenty of properties people write where they do something similar.

I think that is very elegant and a lot nicer than doing this older style.

private SomeType _someObject;
public SomeType SomeObject 
{ 
    get 
    { 
        if (_someObject == null)
        {
            _someObject = giveMeSomeObject(); 
        }
        return _someObject;
    } 
}

Getting Around a Lack of Interfaces With Partial Classes

One pain point which comes along often when working with others' libraries are the classes that are not open and implementing interfaces. A lot of the classes we developers use every day implement no interfaces. Since the class is out of my control, I obviously cannot give it an interface, so I need some other way to work with it. This creates a problem when we need to mock out the class. There are ways in which we can get around this though.

Wrapping Classes

In my opinion, the most dependable workaround to be able to mock out and test a class is creating an interface-implementing wrapper around the class we want to mock and using that instead. This one works very well, but it forces you to create an interface and a class even though there is already a class in existence.

Partial Class Interface

As the name of this post says, partial classes can be very important when presented with this problem. If a class is not implementing an interface, but it is a partial class, you can give it an interface it is already implement.

If a class is partial you can give it an interface which defines the methods it already implements.

So now I am going to present an example. For this example, we will have a class called "BrendanMailer". This class is not implementing an interface, which means that if we want to remove this dependency we need to come up with some solution that lets us program against an interface.

public partial class BrendanMailer
{
    public void SendEmail()
    {
    }

    public void SomeNonImportantMethod()
    {
    }
}

For this we could obviously use the wrapper method, but we can also do something a lot easier. Thanks to the smart creator of that class, there is a partial keyword in there. This allows us to leverage a very powerful trick, because we can now create our own interface. The interface can include only the methods we want it to, which is in some ways better than if the interface had been predefined.

public interface IBrendanMailer
{
    void SendEmail();
}

So now I have a custom interface to work with and program against. I now just add that into another part of this partial class and tell that one I am implementing the interface. I don't have to implement the methods, because they already are implemented in the original part of this partial.

public partial class BrendanMailer : IBrendanMailer
{
}

In my production code I will inject the BrendanMailer class, and in the tests I will mock it out or use a fake or something. This is very powerful and doesn't clutter much at all, because I can hide this partial away in a folder in my project and ignore it for a long time.