Using F# for testing
Twenty six low-risk ways to use F# at work (part 3)
Last updated
Was this helpful?
Twenty six low-risk ways to use F# at work (part 3)
Last updated
Was this helpful?
This post is a continuation of the previous series on -- how can you get your hands dirty with F# in a low-risk, incremental way, without affecting any mission critical code?
In this one, we'll talk about using F# for testing.
Before moving on to the content of the post, here's the full list of the twenty six ways:
Part 1 - Using F# to explore and develop interactively
Part 2 - Using F# for development and devops scripts
Part 3 - Using F# for testing
Part 4. Using F# for database related tasks
Part 5: Other interesting ways of using F#
If you want to start writing useful code in F# without touching core code, writing tests is a great way to start.
Not only does F# have a more compact syntax, it also has many nice features, such as the "double backtick" syntax, that make test names much more readable.
As with all of the suggestions in this series, I think this is a low risk option. Test methods tend to be short, so almost anyone will be able to read them without having to understand F# deeply. In the worst-case, you can easily port them back to C#.
Just like C#, F# can be used to write standard unit tests using the standard frameworks like NUnit, MsUnit, xUnit, etc.
Here's an example of a test class written for use with NUnit.
As you can see, there's a class with the TestFixture
attribute, and a public void method with the Test
attribute. All very standard.
But there are some nice extras you get when you use F# rather than C#. First you can use the double backtick syntax to create more readable names, and second, you can use let
bound functions in modules rather than classes, which simplifies the code.
The double backtick syntax makes the test results much easier to read. Here is the output of the test with a standard class name:
vs. the output using the more friendly name:
So if you want to write test names that are accessible to non-programmers, give F# a go!
Often, you might want to run the unit tests programmatically. This can be for various reasons, such as using custom filters, or doing custom logging, or not wanting to install NUnit on test machines.
Here's an example:
You can run these tests directly in F# interactive using code like this: run simpleTest
.
You can also combine these tests into one or more lists, or hierarchical lists of lists:
Finally, with Fuchu, the test assembly becomes its own test runner. Just make the assembly a console app instead of a library and add this code to the program.fs
file:
If you do need to use an existing test runner (such as the NUnit one), then it's very simple to put together a simple script to do this.
I've made a little example, below, using the Nunit.Runners
package.
All right, this might not be the most exciting use of F#, but it does show off F#'s "object expression" syntax to create the NUnit.Core.EventListener
interface, so I thought I'd leave it in as a demo.
Here's a snippet:
Here's a very simple example:
There are also a number of shortcut operators such as =?
and >?
that allow you to write your tests even more simply -- no asserts anywhere!
Let's say that we have written a function that converts numbers to Roman numerals, and we want to create some test cases for it.
We might start writing tests like this:
But the problem with this approach is that it only tests a very specific example. There might be some edge cases that we haven't thought of.
A much better approach is to find something that must be true for all cases. Then we can create a test that checks that this something (a "property") is true for all cases, or at least a large random subset.
For example, in the Roman numeral example, we can say that one property is "all Roman numerals have at most one 'V' character" or "all Roman numerals have at most three 'X' characters". We can then construct tests that check this property is indeed true.
So, let's see how we'd use FsCheck for our Roman numerals.
First, we define some properties that we expect to hold for all Roman numerals.
With this in place we create tests that:
Create a property checker function suitable for passing to FsCheck.
Use the Check.Quick
function to generate hundreds of random test cases and send them into that property checker.
Here are the results of the test. You can see that 100 random numbers have been tested, not just one.
If we changed the test to be "Test that roman numerals have no more than TWO Xs", then the test result is false, and looks like this:
In other words, after generating 33 different inputs, FsCheck has correctly found a number (30) that does not meet the required property. Very nice!
Not all situations have properties that can be tested this way, but you might find that it is more common than you think.
For example, property based testing is especially useful for "algorithmic" code. Here a few examples:
If you reverse a list and then reverse it again, you get the original list.
If you factorize an integer and then multiply the factors, you get the original number.
But even in Boring Line-Of-Business Applications?, you may find that property based testing has a place. For example, here are some things that can be expressed as properties:
Roundtripping. For example, if you save a record to a database and then reload it, the record's fields should be unchanged.
Similarly, if you serialize and then deserialize something, you should get the original thing back.
Invariants. If you add products to a sales order, the sum of the individual lines should be the same as the order total.
Or, the sum of word counts for each page should be the sum of the word count for the entire book.
Rounding. If you add ingredients to a recipe, the sum of the ingredient percentages (with 2 place precision) should always be exactly 100%.
Similar rules are needed for most partitioning logic, such as shares, tax calculations, etc.
Making sure you get the rounding right in situations like this is where FsCheck shines.
FsCheck is also very useful for doing refactoring, because once you trust that the tests are extremely thorough, you can confidently work on tweaks and optimization.
Some more links for FsCheck:
For more on property-based testing in general, look for articles and videos about QuickCheck.
In addition to doing testing, FsCheck can be used to create random dummy data.
For example, below is the complete code for generating random customers.
When you combine this with the SQL Type Provider (discussed later) or CSV writer, you can easily generate thousands of rows of random customers in a database or CSV file. Or you can use it with the JSON type provider to call a web service for testing validation logic, or load testing.
(Dont worry about not understanding the code -- this sample is just to show you how easy it is!)
And here is a sampling of the results:
If you're using F# to write test cases for code written in C#, you may want to create mocks and stubs for interfaces.
Both are easy to do, and in a way that is similar to Moq.
Here's some Moq code in C#:
And here's the equivalent Foq code in F#:
For more on mocking in F#, see:
But what language should you write the automation in? Ruby? Python? C#? I think you know the answer!
Below is a snippet taken from the Canopy site. As you can see, the code is simple and easy to understand.
If you're not familiar with Behaviour Driven Development (BDD), the idea is that you express requirements in a way that is both human-readable and executable.
The standard format (Gherkin) for writing these tests uses the Given/When/Then syntax -- here's an example:
For example, here's the full implementation of the scenario above.
The C# equivalent has a lot more clutter, and the lack of double backtick syntax really hurts:
Unit tests (FsUnit, Unquote) and property-based tests (FsCheck).
Automated acceptance tests (or at least a smoke test) written in BDD (TickSpec) driven by browser automation (Canopy).
Both types of tests run on every build (with FAKE).
There's a lot of advice on test automation out there, and you'll find that it is easy to port concepts from other languages to these F# tools. Have fun!
The code for this section is .
One simple way to do this is to use the which lets you organize tests directly, especially parameterized tests, without any complex test attributes.
The code above is .
.
The code above is .
The is familiar to all of us, but there are other ways to write tests. Learning to code in different styles is a great way to add some new techniques to your repertoire and expand your thinking in general, so let's have a quick look at some of them.
First up is , which replaces Assert
with a more fluent and idiomatic approach (natural language and piping).
The above code is .
A very different approach is used by . The Unquote approach is to wrap any F# expression in and then evaluate it. If a test expression throws an exception, the test will fail and print not just the exception, but each step up to the point of the exception. This information could potentially give you much more insight in why the assert fails.
The above code is .
The code for this section is .
This is where can help. FsCheck is a framework designed for exactly this kind of property-based testing. It's written in F# but it works equally well for testing C# code.
More generally, if you calculate things via two different paths, you should get the same answer ()
(e.g. ).
See this for other ideas.
I have written and .
.
.
.
(PDF)
Fascinating talk on () (videos)
The code for this section is .
In C# you might use or . In F# you can use object expressions to create interfaces directly, or the .
And you need to mock external services such as SMTP over the wire, there is an interesting tool called , which is .
In addition to unit tests, you should be doing some kind of automated web testing, driving the browser with or .
To make your life even easier, try using , a web testing framework built on top of Selenium and written in F#. Their site claims "Quick to learn. Even if you've never done UI Automation, and don't know F#.", and I'm inclined to believe them.
Also, FAKE integrates with Canopy, so you can .
The code for this section is .
If you are using BDD already with .NET, you're probably using or similar.
You should consider using instead because, as with all things F#, the syntax is much more lightweight.
Examples taken from the site.
You can of course combine all the test techniques we've seen so far ():