Search code examples
f#xunitfsunit

XUnit/FsUnit framework throwing "Object reference not set to an instance of an objct"


I have written this simple test case for my code

module CustomerTests
open Xunit
open FsUnit
open MyProject.Customer
open MyProject.Customer.Domain
    
module ``When upgrading customer`` = 
  let customerVIP = {Id = 1; IsVip = true; Credit = 0.0M}
  let customerSTD = {Id = 2; IsVip = false; Credit = 100.0M}
  [<Fact>]
  let ``should give VIP customer more credit`` () =
    let expected = {customerVIP with Credit = customerVIP.Credit + 100.0M }
    let actual = upgradeCustomer customerVIP
    actual |> should equal expected

Very surprisingly this code fails with error

[xUnit.net 00:00:00.64] CustomerTests+When upgrading customer.should give VIP cstomer more credit [FAIL]
  Failed CustomerTests+When upgrading customer.should give VIP cstomer more credit [3 ms]
  Error Message:
  System.NullReferenceException : Object reference not set to an instance of an object.
  Stack Trace:
    at CustomerTests.When upgrading customer.should give VIP cstomer more credit() in /Users/user/code/fsharp/CustomerProject/CustomerTests.fs:line 12

But line 12 is just a record being created so its not possible for that line to throw an Object reference not set to an instance of object. This is totally puzzling me.

In the dotnet fsi repl I can execute all my method and there is no object reference problem in my function which are being called from my tests here.


Solution

  • As this SO answer explains, XUnit loads the test in a way that skips initialization of those values. One easy fix is to use a class instead of a module:

    type ``When upgrading customer``() =
    
        let customerVIP = {Id = 1; isVip = true; Credit = 0.0M}
        let customerSTD = {Id = 2; isVip = false; Credit = 100.0M}
    
        [<Fact>]
        let ``should give VIP cstomer more credit`` () =
            let expected = {customerVIP with Credit = customerVIP.Credit + 100.0M }
            let actual = upgradeCustomer customerVIP
            actual |> should equal expected
    

    That way, initialization of those values happens as it should.