Online project templates, NuGet, and unit testing with F# in Visual Studio 2012

In this blog post, I show off a number of F# integration features in Visual Studio 2012, by walking through an end-to-end scenario of authoring and testing an F# library.   The code itself is not the focus; rather, I’ll focus on the IDE tooling as we walk through the scenario.   In the end, we’ll have a small application and library supported by unit tests, but along the way we’ll also learn more about a smattering of IDE features including online project templates and NuGet.  I expect there will be something new everyone can learn from this blog, regardless of whether you’re an F# novice or an experienced Visual Studio developer.  So let’s get to it!

The ‘New Project’ Dialog

In Visual Studio, when you want to create a new application or library, you start by selecting ‘New Project’, which brings up the New Project Dialog (NPD).  The NPD is filled with a variety of project templates, which help you create starter projects that contain basic project files, references, and sometimes some starter source code, in order to make it easy to get off the ground for various scenarios.  In Visual Studio 2012, the NPD comes with 5 F# project templates, pictured below.

b01

The “F# Application” and “F# Library” are probably the most commonly-used templates; they create F# EXEs and DLLs respectively.  The “F# Tutorial” project starts you off with an F# script with lots of comments and short examples, and serves as a quick tour of some language features and syntax examples.  The “F# Silverlight Library” is used for creating a library that targets Silverlight 5, and the “F# Portable Library” is used if you want to create a single DLL that can run on Silverlight 5, on the Windows desktop, or as part of a new Windows 8 app.  Most folks know about this portion of the NPD, as you visit this dialog each time you create a new project.

Something that is perhaps less well-known is that there are a variety of online templates available directly from the NPD as well.  In the left-hand pane, if you select ‘Online’, then ‘Templates’ and ‘Visual F#’ you can see lots more project templates for creating starter projects that use F# in a various of frameworks:

b02

These templates have been contributed by the community to the Visual Studio Gallery (from the website, you can also browse for templates).  We’ll see how easy and useful it can be to take advantage of these online templates in a moment.  But while we’re looking at the NPD, I’ll also point out that samples are also available from the left-hand pane:

b03

I’ll discuss both online samples from the NPD, as well as other places to get F# samples, in a future blog post; for now I just wanted to point out this way to obtain some F# samples right from inside Visual Studio.
 

Creating an F# application and library

For the purpose of exposition for the rest of this blog post, it is useful to have a small sample F# application & library on-hand, so let’s create one.  Since this blog is about Visual Studio tooling for F#, and not so much about code, I’ll resort to a trite but familiar example, with my apologies to those who are tired of seeing F# compute prime numbers.  I’ll start with a new F# Library project with this code:

module PrimesLib

open Microsoft.FSharp.Collections

let odds =
let limit = System.Int32.MaxValue |> float |> sqrt |> int
[3..2..limit]

let isPrime n = // naïve implementation
2::odds |> Seq.forall (fun x -> n%x <> 0 || n=x)

and then I’ll try it out it by adding an F# Application to the solution, add a project reference to my library, and putting the code

open PrimesLib

[2..20] |> List.filter isPrime |> printfn "%A"

in the app.  I set the application as the startup project, build, and run, and I see the expected output:

[2; 3; 5; 7; 11; 13; 17; 19]

Now that we have a simple library and app, let’s show off some Visual Studio 2012 features.

Unit testing with F#

In Visual Studio 2012, F# works with MSTest, and there is a good online template to get started.  I’ll add a new project to our solution, and then in the NPD, click ‘Online’ in the left pane, and then type “F# mstest” in the search box at the upper-right:

b04

That’s the template we want.  I create a project from the template (if this is my first time using this online template, I’ll be prompted to download & install the template after agreeing to any license terms an online template may contain), which starts us with starter source code for our test library:

namespace UnitTestProject1

open System
open Microsoft.VisualStudio.TestTools.UnitTesting

[<TestClass>]
type UnitTest() =
[<TestMethod>]
member x.TestMethod1 () =
let testVal = 1
Assert.AreEqual(1, testVal)

Let’s replace the sample test method with our own code that gives us some confidence that isPrime is working correctly.  I’ll add a project reference from the unit test project to my primes library, and then replace the unit test method with

[<TestMethod>]
member x.TestIsPrime() =
let expected = [2;3;5;7;11;13;17;19]
let actual = [2..20] |> List.filter PrimesLib.isPrime
Assert.AreEqual(expected, actual)

Now we can run the test by selecting ‘TEST\Run…\All Tests’ from the VS menu, and VS will run the unit tests:
b05

Great!  We have a passing unit test.  Now we can evolve our code with more confidence.  Perhaps next I’m trying to discover which digit is most common for prime numbers to end in.  I might want to add the function

let finalDigitOfPrimesUpTo n =
[|2..n|]
|> Seq.filter isPrime
|> Seq.groupBy (fun i -> i % 10)
|> Seq.map (fun (k, vs) -> (k, Seq.length vs))
|> Seq.sortBy fst
|> Seq.toList

to get a sample of the data for all the primes up to N.  I can run it from my app by adding this code

printfn "%A" (finalDigitOfPrimesUpTo 500000)

which eventually prints

[(1, 10386); (2, 1); (3, 10382); (5, 1); (7, 10403); (9, 10365)]

showing me that primes appear to be pretty evenly distributed among numbers ending in the digits 1, 3, 7, or 9. 

Let’s add a unit test for this code:

[<TestMethod>]
member x.TestFinalDigits() =
let expected = [(1,10386); (2,1); (3,10382); (5,1); (7,10403); (9,10365)]
let actual = PrimesLib.finalDigitOfPrimesUpTo 500000
Assert.AreEqual(expected, actual)

I notice that this computation takes a while to run—about 12 seconds on my machine.  A very simple way to speed this up is to do the computations for each number in parallel.  I happen to know that the F# Powerpack contains a ‘PSeq’ module, which works like ‘Seq’, but runs functions like ‘filter’ and ‘map’ in parallel.  I’d like to try applying it to this code, but how do I obtain the F# Powerpack to use in my solution?  NuGet to the rescue!

NuGet in Visual Studio 2012

NuGet is package management system that’s integrated into Visual Studio 2012, making it very easy to obtain and use a variety of libraries in your project.  I can right-click on my library project to find ‘Manage NuGet Packages…’ on the context menu in VS:
b06

which brings up the dialog pictured below for NuGet.  I can type ‘fsharp’ (note: not ‘F#’; the search here does not like the ‘#’ character) in the search box in the upper-right, and see that

b07

there are a lot of packages written for (and in) F#.  In this case, I can just click on the FSPowerPack.Community package, click install, agree to the license terms, and then I can see that the Powerpack has been added to my library project if I look at the references:

b08

Now in the code for finalDigitOfPrimesUpTo, I can replace each “Seq.” with “PSeq.” and if I rerun my app, I see that the running time on my machine has gone down to about 3 seconds (previously it took about 12).  NuGet makes it extremely easy to obtain useful libraries and integrate them into your projects without ever leaving the Visual Studio 2012 IDE.

Working around a minor unit testing bug

If I rerun the unit tests at this point, I’m in for a little surprise:

b09

The unit test fails with

FileLoadException: Could not load file or assembly 'FSharp.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

The F# Powerpack package I added was (at the time I authored this blog post; it may have since been updated) built against F# in Visual Studio 2010, and has a reference to FSharp.Core 4.0.0.0 (the F# runtime in Visual Studio 2010).  In Visual Studio 2012, there’s a newer version of the F# runtime, FSharp.Core 4.3.0.0, which is compatible, but has some new added features.  Things worked fine when I ran this from the app, thanks to bindingRedirect in the App.config file in the console application which declares that it’s fine to use the 4.3.0.0 version instead of the 4.0.0.0 version of FSharp.Core.  Indeed, our unit test project also has the appropriate App.config file, which should allow the CLR to load the newer version of the F# runtime, even though the F# Powerpack claims to depend on the old one.  However a bug* in the MSTest runner means that it ignores the App.config file in the unit test project.  Fortunately, there is a simple workaround you can apply with an MSTest ‘runsettings’ file, and such a file has been included by default in the F# MSTest project template.  Simply select ‘TEST\Test Settings\Select Test Settings File” from the menu in VS, and point it at the MSTest.runsettings file in the unit test project.  Now MSTest will pick up the App.config from the unit tests, and all our tests pass again. 

(* - this bug is present in Visual Studio 2012 at the time of this blog post (September 2012), though it may be fixed in future update to Visual Studio.)

b10

And we’re done – we’ve got a library supported by unit tests, that leveraged both an online project template and a NuGet community package.

Summary

To sum up the experiences in this blog post:

  • F# in Visual Studio comes with a few project templates in the box
  • There are lots more useful templates and samples online, which you can easily obtain from the New Project Dialog
  • Visual Studio also makes it easy to use NuGet to obtain other packages of libraries and samples

I hope you’ve learned something new and useful today!

Brian McNamara
Visual Studio F# Developer