Hello,
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" }
[<Fact>]
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
[...clipped...]
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
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