Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MOQ returning dynamic types as object issue

pologise if this questions has been asked but I couldn't find the answer anywhere.

My problem is when mocking a return method using MOQ where that method returns a dynamic type. I'm using a third part library which uses dynamic times. MOQ seems to cast the dynamic type as object.

Mock<IFacebookHelper> mockFbHelp = new Mock<IFacebookHelper>();
mockFbHelp.Setup(x => x.Get("me")).Returns(new { email = "[email protected]", id="9999" });

Method in the mocked helper.

public dynamic Get(string p)
{
    var client = new FacebookClient(AccessToken);
    return client.Get("me");
}

Code from controller using mocked results.

_facebookHelper.AccessToken = accessToken;
dynamic result = _facebookHelper.Get("me");
int facebookId = int.Parse(result.id);  //This errors as id doesn't exist.

Basically MOQ has returned a dynamic type of object that would require casting as something.

Does anyone know how to get around this problem? I'm assuming it may be because MOQ is not coded in .NET 4 therefore does not support dynamic types?

Edit

Actually I don't think this is a MOQ issue as I created my own mock class and still had the same problem. I'm new to dynamic types though so not sure what's going on.

Edit 2 - Part answered.. Problem nothing to do with MOQ after all

Actually the problem seems to be due to the dynamic type being created in a different assembly. Although I got round my initial problem using a JObject type I still want to figure this out.

namespace MyLib.Tools
{
    public interface IDynTest
    {
        dynamic GetData();
    }
}
namespace MyLib.Tools
{
    public class DynTest : Effect.Tools.IDynTest
    {
        public dynamic GetData() {
            return new { DynamicProperty = "hello" };
        }
    }
}
namespace Warrior.WebUI.Infrastructure
{
    public class UseDynTest
    {
        private readonly IDynTest dynTest;

        public UseDynTest(IDynTest dynTest)
        {
            this.dynTest = dynTest;
        }

        public string RetTest()
        {
            return dynTest.GetData().DynamicProperty;
        }
    }
}
namespace Warrior.Tests
{
    [TestClass]
    public class TestDynTest
    {
        [TestMethod]
        public void TestMethod1()
        {
            //Mock<IDynTest> mockDynTest = new Mock<IDynTest>();
            //mockDynTest.Setup(x => x.GetData()).Returns(new { DynamicProperty = "From Unit Test" });

            DynTestProxy dynTestProxy = new DynTestProxy();

            UseDynTest useTest = new UseDynTest(dynTestProxy);

            string results = useTest.RetTest();

            Assert.AreEqual("From Unit Test", results);
        }
    }
}
namespace Warrior.Tests
{
    public class DynTestProxy:IDynTest
    {
        public dynamic GetData()
        {
            return (dynamic) new { DynamicProperty = "From Unit Test" };
        }
    }
}

There are 3 project indicated by the Namespace MyLib, Warrior.WebUI and Warrior.Tests.
As it is the test fails with an error.. 'object' does not contain a definition for 'DynamicProperty' which occurs on RetTest()

However if I simply move the DynTestProxy class into the Warrior.WebUI project everything works fine. I'm guessing there are problems when sending dynamic types accross different assemblies or something.

like image 339
Paul Johnson Avatar asked Feb 20 '23 06:02

Paul Johnson


1 Answers

I did a quick test:

namespace ConsoleApplication5
{
    public interface IFacebookHelper { dynamic Get(string p); }

    class Program
    {
        static void Main(string[] args)
        {
            Mock<IFacebookHelper> mockFbHelp = new Mock<IFacebookHelper>();
            mockFbHelp.Setup(x => x.Get("me")).Returns(new { email = "[email protected]", id = "9999" });

            dynamic result = mockFbHelp.Object.Get("me");
            int facebookId = int.Parse(result.id);
            string email = result.email;
        }
    }
}

This is working fine. I don't see a problem here.

Are you sure you didn't mix some things up?

Look at the method you posted:

public dynamic Get(string p)
{
    var client = new FacebookClient(AccessToken);
    return client.Get("me");
}

Maybe it should be:

...
return client.Get(p);
...

Is _facebookHelper really using the Mock object? It should be of type IFacebookHelperProxy or something like that during your test.

EDIT:

The problem is your attempt to expose an anonymous type across assembly boundaries, since you can use anonymous type only within the assembly you created them.

So instead of

public class DynTestProxy:IDynTest
{
    public dynamic GetData()
    {
        return (dynamic) new { DynamicProperty = "From Unit Test" };
    }
}

you should use an ExpandoObject:

public class DynTestProxy:IDynTest
{
    public dynamic GetData()
    {
        dynamic r = new ExpandoObject();
        r.DynamicProperty = "From Unit Test";
        return r;
    }
}

or use the InternalsVisibleTo attribute. See here for more information. Also this question may be interesting for you.

like image 121
sloth Avatar answered Feb 28 '23 13:02

sloth