Foq
Foq copied to clipboard
Mock throws InvalidProgramException when Calls() or Raises() infer wrong object kind
Member functions mocked using Foq.ResultBuilder.Calls will throw System.InvalidProgramException when a value type parameter is inferred to be a reference type argument. See the example below.
I'm not sure there is anything Foq can do to mitigate this short of developing an Analyzer. Calls() and Raises() are already marked as RequiresExplicitTypeArguments, but that only ensures the type list ("<...>") exists; it doesn't apply to the individual type args.
However, Foq can easily document this behavior. This issue will also serve that purpose, but it would be more helpful if the information was in the documentation of the Calls() and Raises() functions.
Example
module FoqCallsTests
open System
open Xunit
open Foq
type SomeValueType = int
type SomeRefType = string
type IFoo =
abstract member Foo: byValueArg: SomeValueType * byRefArg: SomeRefType -> unit
[<Fact>]
let ``Foq.Calls with inferred ValueType arg throws InvalidProgramException``() =
let m =
Mock<IFoo>()
.Setup(fun m -> <@ m.Foo(any (), any ()) @>)
.Calls<_ * _>(fun (v, r) -> ()) // <== both args are inferred to be `obj`
.Create()
Assert.Throws<InvalidProgramException>(fun _ -> m.Foo(123, "abc"))
[<Fact>]
let ``Foq.Calls with explicit ValueType arg is okay``() =
let m =
Mock<IFoo>()
.Setup(fun m -> <@ m.Foo(any (), any ()) @>)
.Calls<SomeValueType * _>(fun (v, r) -> ()) // <== arg2 is inferred to be `obj` which is okay
.Create()
m.Foo(123, "abc") // works as expected