Pure functions and testability

When trying to introduce unit tests into an existing project, code dependencies is often a problem. During a teeth-grinding session grappling with this problem I came to think about pure functions.

Pure functions are functions that (according to Wikipedia‘s definition):

  • always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change as program execution proceeds, nor can it depend on any external input from I/O devices, and
  • evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.

Seems to me that pure functions would be a wet dream for unit testing. Imagine, you could pass in whatever the function needed to execute, and then check its return value. No mocking about with mock objects with side effect expectations needed!

But alas, we live in a world with non-pure functions. Even in functional programming, which does explicitly keep any state, you find them. In an object oriented language a primary idea is that objects should carry state. An object has a state. Period. However, if we can be inspired by the notion of pure functions, and make methods that have less dependencies, we will be much better off when it comes to unit testing.

I my experience, the ASP.NET programming model with ASPX code behind files is a model that promotes writing methods that are problematic to create unit tests for.

Take, for example, the following (theoretical, I admit) code behind snippet example:

protected void Page_Load(object sender, EventArgs e)
    {
        ShowOrHideEditButton(Page.User.Identity.Name);
    }
    void ShowOrHideEditButton(string currentUser)
    {
        if (Request.QueryString["user"].Equals(currentUser))
        {
            EditButton.Enabled = true;
        }
        else
        {
            EditButton.Enabled = false;
        }
    }
So, what is the problem here? Actually, there are two problems.

  1. The ShowOrHideMethod is not only dependant on its input parameters, but also on another member variable. When looking at the method signature, you do not see this, and might be misleaded about what the outcome of the methods is dependent on.
  2. The method does not return any value, but has a side-effect on its environment (setting the edit button visibility).

These two issues, makes it troublesome to test the method in a unit test. You have spend time to set up the methods context, and you have to measure the method’s side effects in order to make assesments about its result.

A much better approach would be something like this:

    protected void Page_Load(object sender, EventArgs e)
    {
        EditButton.Enabled = ShowOrHideEditButton(Page.User.Identity.Name, Request.QueryString["user"]);
    }
    bool ShowOrHideEditButton(string currentUserName, string profilePerson)
    {
        return (currentUserName.Equals(profilePerson));
    }
This way, we can easily test the ShowOrHideEditButton method in a unit test without having to use a great deal test code to set up the test context.

For increased testability, I would suggest the following for better method purity:

  • A method should evaluate the same result, given the same argument value(s) and object state.
  • A method execution result should be represented as, in order of preference: 1) a return value, 2) changed object state (mutation), or 3) a side-effect on an I/O device
Share
  • Loc Tan Vo

    Very helpful post! I agree that the ASP.NET programming model with ASPX code behind files promotes writing methods that are problematic to create unit tests for. We have experienced problems with testability regarding code behind files on our project. As you mention, pure functions would be a dream for unit testing. I also agree that functions with a return value are the most preferrable. To test void methods (that don’t change the state of the object), we often have to introduce mock frameworks. In my personal opinion, overuse of mock frameworks (with many expectations) will lead to worse readability of the tests (which often are the best documentation for the code).

    Another thing I’m wondering about: pure functions are nice to test, but since they are independent of the state of the object, they tend to accept many arguments. If the amount of arguments exceed a certain number (maybe 2-3), the function can occure a bit unstructured somehow and difficult to know how to use it. What do you do in these cases? Encapsulate the arguments in an object and send the object into the method instead?

  • Andreas Knudsen

    @Loc: I’d say yes to that, I have great experience with “pure functions”, and I use them all the time. The one drawback I see is that your code after a while starts to read like a “Utilities” project, where it starts to get a bit unclear who “owns” a piece of code. In Vidars Example he might as well called the function UserIsCurrentUser(string u, string c) (which might be argued is more “correct” than ShowOrHideEditButton as it doesn’t actually show or hide anything.) but that method would probably be applicable in many places in your code base, so if you want to keep DRY where does it live? how do you find it again the next time you need to check current username (how do you spot it in the myriad of other “util” methods)? IMHO the way to do this is through team communication, making sure that the entire team agrees what makes sense, so that you know that you would have to look for the UserIsCurrentUser in ProfileUtil for instance, even if you yourself did not write that code. Another alternative is to tightly bind the show/hide functionality to an object that is fed all needed info, does some processing on it and is used by the view to generate the UI.

  • Ole-Martin

    Qi4J is trying to solve part of that problem in Java. Each method call goes through constraints and concerns before the actual implementation is executed. If the execution is successful, different side effects may occur. All these aspects are implemented as separate methods and may be unit tested independently. Check it out here: http://stephan.reposita.org/archives/2008/01/09/qi4j-the-next-java-forget-scala/

  • http://www.kongsli.net vidarkongsli

    Thanks for the comments, guys. You touch on an important point: an object has a state, and instance methods are often dependent on the state. This is a key point that separates object oriented languages from other languages. Hence, there has to be a middle way. I don’t advocate only having pure functions. That would, as Andreas points out, make a lot of “utility” methods. I would, rather, argue that a method should not be dependent on anything else than its parameters and instance state. For example, not dependent on any static methods of other classes. (Static methods tend to become the equivalent of a global variable, which is not good for testing).