Unit testing with F#

I recently heard about a project where the code was written in C#, but where they implemented the unit tests in F#. They did so because they wanted to learn and evaluate F# in a protected environment. I thought that sounded like a very good idea and wanted to try.

I picked the unit tests used in builder pattern blog post. My idea was that the builder pattern would be replaced by abilities built into the language itself. Let’s see if that is a correct assumption.

From Fluent to Composition

This C# code is taken from my builder pattern blog post. It dynamically builds an order to use in the unit test, and is written with a fluent syntax:

            var order = new OrderBuilder()
                .WithSingle()
                .WithStatusInProgress()
                .Build()
                .First();

But, how do we write fluent code in F#. The answer is, we don’t:

Now the concept of “fluent interfaces” and “method chaining” is really only relevant for object-oriented design. In a functional language like F#, the nearest equivalent would be the use of the pipeline operator to chain a set of functions together.

F# for fun and profit

F# is a composable language, using functions as building blocks. Composition can be done in different ways, with function pipelining (|>) or function composition (>>). By defining functions that has the same type as argument and return type, they can be chained together in a very clean and decent way. Let’s see how that works.

The C# model

The C# model that we will test from our F# tests is just a simple order class with two methods:

    public class Order
    {
        public OrderStatus Status { get; set; }

        public void Cancel ()
        {
            Status = OrderStatus.Canceled;
        }

        public void StartProcessing()
        {
            Status = OrderStatus.InProgress;
        }
    }

It is stateful and the methods return void. This type of classes can be written in many ways, but I think this is rather common so I’ll use it even though it’s not perfect for the F# code which we’ll see later.

Create the builder

The builder class in C# is stateful (see blog post referred above), because it has class variable to which each function adds data. Using class variables means that the methods has a side-effect, and side-effects are something that we’ve learned that we should avoid if possible.

The functions in the F# builder are very simple and with no side effects as they operate on their indata (or create new data). The first one creates the order itself and returns it. The next one takes an order as an argument, changes it and returns it:

let withSingle () = 
    Order()

let withStatusInProgress (order : Order) = 
    order.StartProcessing()
    order

In F# we don’t write “return”, the value of the last line is automatically returned. Order() is the same as “new Order()” in C#. Note that if the method “order.StartProcessing” had returned the order, we could have omitted the last line of the second function. But I wanted to keep the C# code as we usually write it, like it would be in a real case.

So, this is the builder for now. We’ll keep it simple and find out later how to handle lists (which we do in the C# builder).

Function pipelining

This is what a test can look like in F#, FsUnit is used to get the nice assert syntax. Here we use pipelining to combine different functions that produces and manipulates the order.

[<Fact>]
let ``Cancel order - pipe test`` () =
    
    //Arrange
    let order = 
        OrderBuilder.withSingle()
        |> OrderBuilder.withStatusInProgress

    //Act
    order.Cancel()

    //Assert
    order.Status |> should equal OrderStatus.Canceled

“OrderBuilder.withSingle” is called to get an order that is used as input the next function “OrderBuider.withStatusInProgress”. The order that is sent to, and received from the functions is not visible in the code. This might be confusing at first, but when you get used to it it’s nice because it keeps you code cleaner.

..the function parameters can often be ignored when doing function composition, which reduces visual clutter.

F# for fun and profit

Function composition

With function composition it’s possible to combine functions in many different ways, and store them in variables. These function variables can then be combined with each other. If we use function composition in our test it would look like this instead:

[<Fact>]
let ``Cancel order composition test`` () =
    
    //Arrange
    let createOrder = 
        OrderBuilder.withSingle 
        >> OrderBuilder.withStatusInProgress

    let order = createOrder()

    //Act
    order.Cancel()

    //Assert
    order.Status |> should equal OrderStatus.Canceled

In this test there is an extra line to actually run the function. The best written tests should be both readable and short, so probably pipelining would be the best choice in this specific example.

Build lists

How do we build lists in a clean and simple way in our tests? First let’s add another function to our builder, “withStatusCancelled”:

let withSingle () = 
    Order()

let withStatusInProgress (order : Order) = 
    order.StartProcessing()
    order

let withStatusCancelled (order : Order) = 
    order.Cancel()
    order

Let’s say the test should build a list with one order that is in progress, and one that is cancelled. By using composition, two functions are defined by combining two other functions:

    //Arrange
    let createInProgressOrder = OrderBuilder.withSingle >> OrderBuilder.withStatusInProgress
    let createCancelledOrder = OrderBuilder.withSingle >> OrderBuilder.withStatusCancelled
    
    let orders = [createInProgressOrder(); createCancelledOrder()] 

To make the code even more compact, the following can be done without losing readability:

    //Arrange
    let orders = [
        (OrderBuilder.withSingle >> OrderBuilder.withStatusInProgress)()
        (OrderBuilder.withSingle >> OrderBuilder.withStatusCancelled)()
    ]

What do you think? Which one is the best? Or does anyone have a better suggestion?

Conclusion

Since F# is a language that is built for composition, it’s great for providing flexible data to tests. The amount of code needed for the OrderBuilder is significantly reduced compared to in C#. Handling lists is very easy and can be kept outside the builder, in the test itself.

Using F# for the unit tests is not only a good and safe way to get used to a functional language. It also makes the tests simpler and reduce boilerplate and the number of lines in your code.

After getting used to it, I also think that it makes the code more readable! (If written in a good way, but that applies to C# too). I recommend you to read more about how to use it as a Domain-Specific Language to take this one step further!


Download the complete code here.

Confused? Want to learn more?
Spend 60 seconds to better understand F#
Want to learn more about building blocks?


Unit testing – Provide flexible data

It’s rather easy to find information about how to write a good unit test in the means of the test itself. But how should we handle the data that we need to test? How can we create test data structures in a flexible way?

As a DDD (Domain-Driven Development) person, I like to be able to read the code as I read a book. This is of course very hard, but something that I strive for. Therefore I often use the builder pattern for unit tests.

Builder pattern

Generally, a good approach is to create the data within the test itself. This makes it easy to see exactly what the test do. But after some tests you often find the same code repeated many times so you start looking for a generic way of generating the data suitable for each little thing you want to test. The builder pattern comes in handy here.

Let’s say you want to test the following test case:

* When you cancel an order, it gets the status cancelled. *

The test

You need to create an order with the status InProgress. Your test will then change the order to Canceled an verify that it worked. In a real system, you would probably have a lot of tests around status changes. Therefore it would be suitable to have code that creates an order in different statuses.

With the builder pattern to generate the order the test might look something like this:

        [Fact]
        public void CancelOrderTest()
        {
            //Arrange
            var order = new OrderBuilder()
                .WithSingle()
                .WithStatusInProgress()
                .Build()
                .First();

            //Act
            order.Cancel();
            
            //Assert
            order.Status.Should().Be(OrderStatus.Canceled);
        }

Let’s start with the “Arrange” part. A new OrderBuilder is created and asked to create a single order with the status InProgress. When looking into the builder later on you’ll see why the .Build() and .First() methods are needed.

The “Act” part here is intended to cancel the order, and the “Assert” checks whether the order has got the status Canceled. The FluentAssertions package is used to get a nice and fluent syntax of the assertions.

The builder

The OrderBuilder is a class with methods that returns the class itself. This is what makes it possible to use the fluent syntax in the test. Only the Build() method returns the actual list of orders:

    public class OrderBuilder
    {
        private List<Order> _orders = new List<Order>();

        public OrderBuilder WithSingle()
        {
            _orders.Add(new Order());
            return this;
        }

        public OrderBuilder WithStatusInProgress()
        {
            _orders.Last().StartProcessing();
            return this;
        }

        public List<Order> Build()
        {
            return _orders;
        }
    }

I chose to prepare the builder to handle many orders, by adding a private list variable in the top of it. Of course that could also be a single order.

The WithSingle and WithStatusInProgress methods both operates on the private class variable and step by step build up the order that the caller of the builder wants to have. More methods can be added and freely combined and called after each other to e.g. build up a list of orders:

        //Arrange
        var orders = new OrderBuilder()
            .WithSingle().WithStatusInProgress()
            .WithSingle().WithStatusNew()
            .Build();

The Build method returns the orders and breaks the chain by not returning the TestBuilder class.

A functional approach

Another approach to the problem is to use a functional way of building up the test data. Sometimes you have a lot of properties, and want to change them in a controlled way to get exact the data you want to test. You can add a method to the builder that lets you create an order this way:

    [Fact]
    public void CancelOrderTest2()
    {
        //Arrange
        var order = new OrderBuilder()
            .WithSingle(o => o.Status = OrderStatus.InProgress)
            .Build()
            .First();

        //Act
        order.Cancel();

        //Assert
        order.Status.Should().Be(OrderStatus.Canceled);
    }

You can from the test set which properties you want to change on the order, and combine with other builder methods if you want. The WithSingle builder method that takes a function parameter looks like this:

    internal OrderBuilder WithSingle(Action<Order> action)
    {
        _orders.Add(new Order());

        action?.Invoke(_orders.Last());

        return this;
    }

It takes a function as an argument, creates an order and applies the function to it.

Conclusion

The builder pattern has helped me a lot and it is always fun to use it! I show it here as I learned it from start, but in every project I use it in a special flavor suitable exactly for that special environment.