fsprojects / Foq

A unit testing framework for F#
http://www.slideshare.net/ptrelford/foq-17062247
Apache License 2.0
79 stars 31 forks source link

Can't mock an abstract class with an "internal set" virtual property #27

Open davidgruar opened 5 years ago

davidgruar commented 5 years ago

Description

Foq throws an exception if you try to mock a C# abstract class containing a virtual property with an internal setter.

Repro steps

Create the following class in a C# project:

public abstract class AbstractClass
{
    public int ConcreteInternalSet { get; internal set; }
    public virtual int VirtualPrivateSet { get; private set; }
    public virtual int VirtualProtectedSet { get; protected set; }
    public virtual int VirtualInternalSet { get; internal set; }
    public abstract int AbstractReadOnly { get; }
}

Create this test in an F# test project:

[<Fact>]
let abstractClassTest() =
    Mock<AbstractClass>().Create() |> ignore

Expected behavior

Test should pass.

Actual behavior

Fails with this error:

System.TypeLoadException : Method 'set_VirtualInternalSet' on type 'Mock.AbstractClassefa0bfaa-f64d-4c8b-b1b2-7eef47cfe38a' from assembly 'Foq.Dynamic, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is overriding a method that is not visible from that assembly.

Stack Trace:

   at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type)
   at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
   at System.Reflection.Emit.TypeBuilder.CreateTypeInfo()
   at Foq.Emit.mock(MockMode mode, Type abstractType, FSharpList`1 otherTypes, FSharpList`1 calls, Object[] args, FSharpOption`1 returnStrategy)
   at Foq.Mock`1.Create()

If you remove the VirtualInternalSet property, the test passes.

Related information

richardjharding commented 5 years ago

Have just hit this when trying to use Foq to mock the Microsoft.Azure.WebjobsDurableOrchestrationContextBase type - I was attempting port the sample here https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-unit-testing#unit-testing-orchestrator-functions to use Foq

It should be noted that I can use Moq in f# to re-create that sample and mock the type without issue but I really like the use of quotations in Foq!

belcher-rok commented 2 years ago

Any progress on this issue? I just ran into it after upgrading to latest Azure.Storage.Blobs library (12.11.0). The Azure.Response type can no longer be mocked:

let resp = Foq.Mock<Azure.Response>().Create()

Fails at runtime with System.TypeLoadException : Method 'set_IsError' on type 'Mock.Responseda15e24f-4b36-4ebb-a375-a1c2b3ef1ec8' from assembly 'Foq.Dynamic, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is overriding a method that is not visible from that assembly.

Edit: I just noticed that the IsError property is not even virtual. Now I'm really confused.