Unit Testing F# Projects

I am a big believer of unit tests and as I write more and more code, I suffer what sociologists call “confirmation bias” whereby I keep finding more and more reasons to confirm that I am right.  But I am at the point where I don’t believe in developer documentation (sorry Sandcastle), reflector (sorry Redgate), code comments, or architectural diagrams.  I believe in the code, the whole code, and nothing but the code.  Or as Rasheed Wallace might say if he was a coder versus a professional basketball player: “Code Don’t Lie!”.

And the only code that tells you what a module is doing is the unit tests.  If you want to see how the module behaves, look at the green unit tests.  If you want to see how the module is supposed to behave but is not, look at the red unit tests.  If you want to see how the module might or might behave because the code is out of control, look for the non-existent unit tests.

So when I started writing code in F#, the unit tests went along for the ride.  F# folks will tell you to use the REPL to get your code working and/or use a unit test project in F#.  I don’t do either because:

1) The REPL is designed for quick prototyping, not for having a durable, cantonal example of module behavior. Having a full suite of unit tests gives you code coverage, tests at the build, and a fail-proof way of documenting the code’s behavior.

2) Most of the other developers I work with are CSharpers.  Having the unit tests in C# allows them to understand the behavior in a language in which they are familiar.  Since the tests need to communicate the working code’s intent, having that in a language they understand is critical.  They don’t have to understand F# to use a F# module.  Also, porting from C# in MSTest to NUnit in C# is a snap.

So when you add a C# Unit Test project to your solution that has a F# module you want to test, there are a couple of things you need to do.

1) Add a reference from the Unit Test Project to the F# Project (Right Click, Add Reference)

image

2) Add a reference to F#

image

3) If you are using type providers (and who doesn’t) and you have the connection string in the .config file of the working code project, add a .config file to the unit test project and copy over the connection string

image

Note that you code has to reflect that the connection string is being used in 2 different ways by the type provider, as explained in this post.  Your F# code needs to look like this:

  1. type internal SqlConnection = SqlEntityConnection<ConnectionStringName="azureData">
  2.  
  3.  
  4. type public RestaurantAnalysis () =
  5.     
  6.     let connectionString = ConfigurationManager.ConnectionStrings.["azureData"].ConnectionString;
  7.     member public x.GetScoresByMonth () =
  8.         SqlConnection.GetDataContext(connectionString).Restaurants
  9.             |> Seq.map(fun x -> x.InspectionDate.Value.Month, x.InspectionScore.Value)
  10.             |> Seq.groupBy(fun x -> fst x)
  11.             |> Seq.toList

4) Finally, you have to rebuild the F# project each time you want the unit tests to pick up changes.  That is different from a C# unit test project referencing a C# working code project.

Finally, not related to unit testing but too short for a blog post, if you are using the type providers (and who doesn’t) and you need to expose your classes publicly, you can’t use the SqlEntity provider – you need to use the SqlData provider.  The catch is that SqlData does not work with Azure Sql Storage as far as I can tell.  In my case, I used SqlEntity and exposed tuples and custom types publicly.  Not the best, but still better than using C# and Entity Framework…

Advertisements

One Response to Unit Testing F# Projects

  1. Pingback: F# Weekly #6, 2014 | Sergey Tihon's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: