I'm trying to setup a basic FAKE F# project that can run FsUnit but I cannot figure out how to solve the Method not found: 'Void FsUnit.TopLevelOperators.should(Microsoft.FSharp.Core.FSharpFunc`2<!!0,!!1>, !!0, System.Object)'
errors.
I have read the following posts that seem to be related, but I'm apparently still not grokking it:
- Main github issue
- FSharp.Core packaging guidelines
- FsUnit unable to test portable library (SO)
- Another github issue
I have created a JunkTest
library project with the following setup:
paket.dependencies
source https://www.nuget.org/api/v2
nuget FAKE
nuget FSharp.Core
nuget FsUnit
nuget NUnit
nuget NUnit.Console
paket.references
FSharp.Core
FsUnit
NUnit
JunkTest.fs
module JunkTest
open FsUnit
open NUnit.Framework
[<Test>]
let ``Example Test`` () =
1 |> should equal 1 // this does not work
//Assert.That(1, Is.EqualTo(1)) // this works (NUnit)
build.fsx (relevant part)
Target "Test" (fun _ ->
!! (buildDir + "JunkTest.dll")
|> NUnit3 (fun p ->
{p with OutputDir = "TestResults" }
)
)
Output
I see that FSharp.Core.dll is being copied from the local packages
directory: Copying file from "c:\Users\dangets\code\exercism\fsharp\dgt\packages\FSharp.Core\lib\net40\FSharp.Core.dll" to "c:\Users\dangets\code\exercism\fsharp\dgt\build\FSharp.Core.dll".
And the nunit3-console execution: c:\Users\dangets\code\exercism\fsharp\dgt\packages\NUnit.ConsoleRunner\tools\nunit3-console.exe "--noheader" "--output=TestResults" "c:\Users\dangets\code\exercism\fsharp\dgt\build\JunkTest.dll"
I have tried to add a app.config
file with the in the test project root directory with the following but it doesn't seem to solve the issue (NOTE I am not using Visual Studio - do I need to do anything special for the project to include the app.config
file?):
<?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-4.3.1.0" newVersion="4.3.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Any and all help is appreciated.
EDIT: The solution was that I was not properly setting up the App.config
file to get included in the build. All of the answers that said "just add this to your App.config
file" didn't help me because VSCode doesn't add this to the fsproj
file automatically.
The part that I added is:
<None Include="App.config" />
In the ItemGroup
that contains the other <Compile Include=Foo.fs>
lines.
This happens because of
FSharp.Core
version mismatch. See, your application references one version ofFSharp.Core
andFsUnit
references another version. This means that theFSharpFunc<_,_>
type is going to be different (coming from different assemblies) for you andFsUnit
, which in turn means that theshould
function exported byFsUnit
is not the same function that your code is looking for, because it has a parameter of a different type.This is where the
bindingRedirect
comes in. You're absolutely correctly added it toapp.config
, but from your question about whether you're doing it correctly, I get a suspicion that you might not. The thing withapp.config
is, it's not actually the program configuration. Rather, it's the source code for program configuration. At compile time, this file gets copied tobin\Debug\Your.Project.dll.config
, and only then it will get picked up at runtime. If you didn't add this file to thefsproj
project file (which, I suspect, might be the case), then it's not getting copied to the right place during build, and thus isn't getting picked up at runtime.Another reason for it still not working may be that you've specified an incorrect version of
FSharp.Core
in yourapp.config
file. Which brings me to the next point.Crafting that file by hand is a bit fragile: when you upgrade
FSharp.Core
to a new version (or Paket does it for you), you may forget to fix it inapp.config
and even if you don't, it's a bit of a hassle. But Paket can help you with that: if you add theredirects: on
options to yourpaket.dependencies
file, Paket will add thebindingRedirect
cruft to yourapp.config
automatically: