I'm looking for advice on how to get this working, so comments are very welcome here. (And I have tried searching on Google, but the keywords I've been using have not returned anything relevant.)
*** Update (Resolution) ***
When I tweeted out this article, I got lots of responses. That's one thing I really like about the F# community: they are always ready to help. It turns out the issue was easy to resolve. I just needed to change the F# Runtime version from 4.0 to 3.0 in the project settings:
After that, the tests ran successfully. Feel free to read the rest of this article if you're curious, but it turns out the solution was pretty simple (once you know about it).
If you'd like to grab the project, you can get it on GitHub: jeremybytes/mocking-tests.
When I started exploring testing using FsUnit, I got error messages when I tried to use Foq. To narrow things down, I eliminated as many variables as possible. That meant using the sample from the "Foq.Usage.fsx" file that came down when grabbing the package from NuGet.
To setup the project, I created a new F# library. Then from NuGet, I got the following packages: "Foq" (v1.7.1), "NUnit" (v3.5.0), and "NUnit3TestAdapater" (v3.6.0).
The Sample Test
Here's the sample test copied from the usage file into the code file (in Library1.fs):
This test should pass, but it fails in the Test Explorer:
Here's the error message:
Method not found: 'Foq.ResultBuilder`2<!0,!!0> Foq.Mock`1.Setup(Microsoft.FSharp.Core.FSharpFunc`2<!0,Microsoft.FSharp.Quotations.FSharpExpr`1<!!0>>)'.Unfortunately, I'm not familiar enough with code quotations in F# (and parsing expressions in general) to be able to understand this message. So I did some more work to try to narrow things down.
First, I verified that NUnit and the NUnit3TestAdapater actually work with the F# library. For this, I simply added another test (in Library1.fs):
And the test runner has no problems with this. Here's the passing test and the failing test output:
Working Foq Test in F# Interactive
The reason I think the test runner might be the problem is that I was able to successfully run the test in F# interactive. To try to eliminate variables, I created a new script file with just the following (in Script.fsx):
When executing this script, I get the following output:
This shows me that we're not getting any errors just by running this script with Foq and the code quotation.
Testing for Failure
Just to make sure that things were working, I decided to invert the test. I changed the mock object so that it would return "false" instead of "true", but I left the assertion unchanged:
When executing this script, we get the NUnit test failure message:
So that is working as expected.
Trying the Console Runner
My next step to try to isolate this to the test runners was to try the NUnit Console Runner. For this, I grabbed the "NUnit.ConsoleRunner" (v3.5.0) package.
When running the library tests from the command line, I got the same result: 1 passed, 1 failed:
And digging through the output file, I came across the same message as when running the tests in Visual Studio.
So the question for the F# gurus out there: Is there a way to get the NUnit test runners to work with this Foq example?
Unfortunately, I'm not at the point where I can parse the error message, so I don't know if it's a simple fix, or something that won't work because of the way that the NUnit test runners are implemented.
*** Update (Resolution) ***
When I tweeted out this article, I got lots of responses. That's one thing I really like about the F# community: they are always ready to help. It turns out the issue was easy to resolve. I just needed to change the F# Runtime version from 4.0 to 3.0 in the project settings.
I know that some folks are saying, "Well just run your tests as a script." And that would work for some scenarios.
What I'm exploring is how to use F# for testing C# code. For that, I want the test runner experience to be as seamless as possible. I'm currently using NUnit, and I prefer to have the integrated test runner in Visual Studio. So that's why I'm looking into this further.
I'll be sure to post solutions because I'd really like to get this working, and I'm sure I'm not the only one.