Why do I receive an error when initializing a record with an option?
The following line fails my unit test:
let name = { First=String20("Scott"); Last=String20("Nimrod"); Suffix=None }
Test Result:
Result StackTrace: at CreateModuleViewModel.Tests.submit module() Result Message: System.MissingMethodException : Method not found: 'Void Name..ctor(String20, String20, Microsoft.FSharp.Core.FSharpOption`1)'.
The test is as follows:
module CreateModuleViewModel.Tests
open FsUnit
open NUnit.Framework
open UILogic.State
open CreateModule.UILogic
open ManageModule.Entities
[<Test>]
let ``submit module`` () =
// Setup
let viewModel = CreationViewModel()
let name = { First=String20("Scott"); Last=String20("Nimrod"); Suffix=None }
let duration = { Hours=1; Minutes=30; Seconds=0 }
let moduleItem = { Author=name; Duration=duration }
// Tets
viewModel.Add(moduleItem)
// Verify
viewModel.Modules.Head = moduleItem |> should equal true
The record definition is as follows:
type String20 = String20 of string
type Name = {
First:String20
Last:String20
Suffix:String20 option
}
Why am I receiving this error?
The most common cause for the MissingMethodException
is that some of your dependencies is compiled against a different version of FSharp.Core.dll
than the unit test library.
The way to solve this is to add bindingRedirect
to your app.config
. I think most unit test runners will respect the binding redirect too, and so this should fix the problem.
Mark Seemann has a blog post about this. Stealing his example, you need something like:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="FSharp.Core"
publicKeyToken="b03f5f7f11d50a3a"
culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-99.99.99.99"
newVersion="4.3.1.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
The newVersion
will be either 4.3.1.0
(Visual Studio 2013) or 4.4.0.0
(Visual Studio 2015). I changed the oldVersion
here to a range that should include all versions that may be around.
The reason why this causes MethodMissingException
is a bit subtle - but without the redirect, the runtime things that e.g. option<T>
from one F# Core is not the same thing as option<T>
from another version of F# Core and so it cannot find method that it was expecting.