Wednesday, March 25, 2020

Learning F# - Step 3

This next step for me is an important one. Unit testing. I use unit testing, especially test driven development, a lot. For me TDD is a design tool that helps me design good code. Unit tests provide an awful lot of feedback about code that helps a developer learn, grow, and get better. (I'll try to create a separate post about the benefits of unit testing.)

All that being said, I like to know how to approach unit testing in a new language. Many people like to go after language constructs and idiomatic patterns first. These are important, but I like knowing how to test my code first. I won't always write unit tests as I'm learning and exploring, but understanding the approach to testing in a new language uncovers a LOT about the language itself.

F# makes unit testing easy, for a C# developer. F# supports NUnit and xUnit. I've been using xUnit for most of my C# projects, so I decided to try xUnit with F#.

To get started, I created a unit test project in F# using the following call in the .NET CLI:

dotnet new xunit --language f#
This call created a unit test project with the xUnit reference baked in. I then modified the Tests.fs file to be the following:
module Testing

open System
open Xunit

let AddOne x =
    x + 1

let TestAddOne () =
    let result = AddOne 5
    Assert.Equal(result, 6)

I immediately see some things that are familiar, and some things that are new. The module definition seems very much like the namespace structure from C#. Turns out, it is very similar. The module keyword packages the code that follows (because F# uses indentation and spacing instead of curly braces to separate code) into a coherent unit, just like the namespace keyword does in C#. The open System and open Xunit lines also look like import statements in C#. These are just like import statements from C#! The other familiar elements are the [<Fact>] attribute and the Assert.Equal() call. These are familiar elements of XUnit and work as expected.

To exercise my test, I created a function, AddOne, that takes a parameter and adds 1 to it. My test calls AddOne and captures the return value in the variable result. I then assert that my result is what I expect it to be. When I run the command:

dotnet test
I see that my unit test passes!

If you are following along at home, you've noticed that the default contents of the Tests.fs file is different from mine. It is useful to look at it as well. The default file contains a sample unit test with a strange name. The name is contained within a set of ``. This construct turns the contents contained within the `` set into an identifier that would not normally be a legal identifier. This "trick" allows one to create names in F# that can be used as a Domain Specific Language (DSL) or to create more readable output. That's a handy feature when doing a lot of unit testing!

Now that I have created my Hello World program, understand the build and project structure, and can create some basic unit tests, I'm itching to do something real with the language. That's next!

No comments:

Post a Comment