1

As a learning exercise, I'm trying to test some F# code using MSTEST. I've run into a problem that is driving me crazy, not because I can't work around it, but because I don't understand how to properly add a type annotation to determine what overloaded method I'm using (meaning I haven't properly learned what I'm trying to learn).

Anyway, here is a simplified example of the non-working code:

[<TestClass>]
type MyTests () =
 [<TestMethod>]
 member this.SyntaxTest () =
 Assert.AreEqual<bool>(true, false) // compiles 
 Assert.AreEqual<bool>(expected=true, actual=false) // compiles
 Assert.AreEqual<bool>((true : bool), (false : bool)) // compiles
 Assert.AreEqual<bool>(true, false, "message string") // fails to compile
 Assert.AreEqual<bool>(true, false, ("message string" : string)) // fails to compile
 Assert.AreEqual<bool>(expected=true, actual=false, message="message string") // fails to compile
 // Simple work around that doesn't answer how to properly make the Assert.AreEqual call:
 if (true <> false) then do
 Assert.Fail("Fail message")
 

As can be seen in the comments, the version using only bool inputs works fine using several different versions of type and parameter notations. However, as soon as I add a message string, nothing I can think of to do will make it compile.

The fail code I get is:

FS0041: A unique overload for method 'AreEqual' could not be determined based on type information prior to this program point. A type annotation may be needed. Known types of arguments: bool * bool * string Candidates: - Assert.AreEqual<'T>(expected: 'T | null, actual: 'T | null, message: string | null) : unit - Assert.AreEqual<'T>(expected: 'T | null, actual: 'T | null, message: string | null, [] parameters: obj | null array | null) : unit ....

From the Microsoft documentation link there are an awful lot of different Assert.AreEqual methods with slightly different signatures, but I apparently have no idea how to tell the F# compiler which one I want. From what I've read, I thought that adding ":string" or "message=" might help, but it doesn't.

Does anyone know how to get the compiler to properly resolve the method overload issue? Also, if anyone can link to a definitive resource for this issue, that would be amazing!

asked Mar 17 at 4:46
1
  • related: It can be argued that the idiomatic way to write tests in F# is unquote (I use it with xunit, but it works with any test framework and does not go down the road of depending on a Fluent Assertions library!) stackoverflow.com/a/5669263/11635 Commented Mar 18 at 11:16

1 Answer 1

2

Unfortuanately, this testing framework was written with only C# in mind, which means that the method overload you're trying to call expects "nullable" types:

void AreEqual<T>(T? expected, T? actual, string? message)

(Nullable types are a truly hideous feature of C# that they've had to introduce because null values are so common in that language, but I digress.)

So, to help F# find the correct overload, you have to explicitly make your values nullable:

open System
...
Assert.AreEqual(Nullable true, Nullable false, "message string")

The silver lining in this ugly cloud is that you can at least leave off the explicit <Nullable<bool>> type argument, because F# will infer that for you.

As a workaround, if this is something you need to call often, you could also define your own AreEqual member:

type Assert with
 static member inline AreEqual(expected : bool, actual : bool, message : string) =
 Assert.AreEqual(Nullable expected, Nullable actual, message)

And then you can call it normally:

Assert.AreEqual(true, false, "message string")
answered Mar 17 at 5:09
2
  • Thank you, your answer worked perfectly and was just what I was looking for. Nullable types are discussed in the Microsoft F# documentation (learn.microsoft.com/en-us/dotnet/fsharp/language-reference/…), but there wasn't an example of how it applies to C# calls so I didn't really make the connection. I'm going to leave feedback on that page suggesting that they add some C# examples to make this connection more clear. Commented Mar 17 at 19:59
  • Glad I could help. I should also mention that if you are really just working with bool values, Assert.IsTrue and Assert.IsFalse are better. Commented Mar 18 at 21:17

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.