Unexpected NullReferenceException in (pure?) F# unit test

I’ve been learning F# for the past couple of weeks and I just encountered something quite unexpected.

Can someone explain why? I suspect it’s related to how FsUnit instantiates the test cases… but it also seems inconsistent with the semantic of the language.

Here’s the code:

open Xunit
open FsUnit

type Customer = { name: string }

module Test =

  let j = { name = "John" }

  let unexpectedNRE () = j.name |> should equal "John"

Running dotnet test results in the following error (exception line number corresponds to the last line above):

Test run for $PROJECT/Test/bin/Debug/net6.0/Test.dll (.NETCoreApp,Version=v6.0)
Microsoft (R) Test Execution Command Line Tool Version 17.1.0

  Error Message:
   System.NullReferenceException : Object reference not set to an instance of an object.
  Stack Trace:
     at EssentialFSharpApp.Test.Test.unexpectedNRE()

If I move let j = ... inside the test it works.
Removing the inner module Test makes no difference.

Welcome @acorello!

I swear I’ve run into this exact problem a long time ago, but I’m having trouble remembering the details. Maybe it had to do with Xunit? I would try using NUnit to run your tests and see if that fixes it? Your file should be able to stay the same except open Xunit => open NUnit.Framework and [<Fact>] => [<Test>]

Hi @ntwilson, thank you!

I found and fixed the issue: the tests were in a separate xunit project and it worked after I put back the Program.fs file, which contained a default [<EntryPoint>] just returning zero. Without that file I get the NullReferenceException. It wasn’t obvious to me that file was required and my “no unnecessary code” policy took over. I don’t really understand what’s going on, but at least I can continue.

The problem happened also with NUnit.

Should anyone be interested, this is a repo with a passing test (tag: PASSING) and the failing tests after removing the Program.fs (tag: NRE), with both xunit and nunit.

Back to coding now :pray:

FWIW, it seems to be related to the <GenerateProgramFile>false</GenerateProgramFile> property. If I delete that property, it seems that everything works fine. I’m not entirely sure what exactly that property is supposed to be doing for you (I usually am including tests in a library project instead of an executable project), but to me it seems like all it’s doing is making the test run fail with the NRE.

1 Like

I confirm, that removing GenerateProgramFile and the Program.fs entry from the .fsproj file I can run the tests without NRE.

I’m don’t know why the xUnit project is setup this way: I’ve followed the instructions and used the official template. It would make sense to me to have a “lib” project rather than an “exe” project, or to set GenerateProgramFile to true (the default) and remove Program.fs: the current Program.fs is just a stub anyway; it would be less code.

If I wanted to use that approach would I run dotnet new classlib -lang F# then add the dependencies?

Yep. That’s exactly what I end up usually doing. I have some mistrust for the templates, because they’re not always up-to-date, so I usually start with dotnet new classlib -lang f# and go from there.
But also dotnet new classlib -lang f# vs dotnet new nunit -lang f# vs dotnet new console -lang f# are all just differences in the .fsproj file. The difference between a “classlib” and a “console” is the <OutputType> property in the .fsproj - one would be <OutputType>Library</OutputType>, and the other <OutputType>Exe</OutputType>. (And the “nunit” or “xunit” projects would have some extra dependencies and properties). So you can switch between them without creating a new project just by editing your .fsproj file.

1 Like