4

I'm trying to mock a Visual Studio CommandBars instance. CommandBars implements the non-generic IEnumerable interface. To be able to iterate over the mock, I set up GetEnumerable(). Strangely, this only works if I access the mock.Object as an instance of CommandBars. If I cast is to IEnumerable (as it happens implicitly when using Linq methods) GetEnumerable() suddenly returns null. Can someone explain this behavior?

var mockCommandBars = new Mock<CommandBars>();
IEnumerable bars = new List<CommandBar>();
mockCommandBars.Setup(cb => cb.GetEnumerator()).Returns(bars.GetEnumerator);

var cbs = mockCommandBars.Object;
var cbs1 = cbs.GetEnumerator();  // returns instance
var ecbs = (IEnumerable) cbs;
var cbs2 = ecbs.GetEnumerator(); // returns null!

Edit: I'm using Moq 4.2.1402.2112

Sven Amann
  • 565
  • 2
  • 12

1 Answers1

6

By examining the actual type of

 var cbs = mockCommandBars.Object;

at runtime, it appears that cbs has been wrapped as:

 cbs    {Castle.Proxies.CommandBarsProxy}

And that the cast to IEnumerable interferes with the proxy's behaviour.

You might be able to use the helper method from this post here, to wire access to the proxy's __target property, e.g.

var cbs2 = UnwrapProxy<IEnumerator>(cbs.GetEnumerator());

where

  internal static TType UnwrapProxy<TType>(TType proxy)
  {
     try
     {
        dynamic dynamicProxy = proxy;
        return dynamicProxy.__target;
     }
     catch (RuntimeBinderException)
     {
        return proxy;
     }
  }

Edit

From Here it became clear that the setup wasn't being performed on the underlying _CommandBars.IEnumerable interface

You can change the setup explicitly:

     var cbs = mockCommandBars.As<_CommandBars>().As<IEnumerable>();
     cbs.Setup(cb => cb.GetEnumerator()).Returns(bars.GetEnumerator());

     var ecbs = (IEnumerable)cbs.Object; // The cast is now redundant.
     var cbs2 = ecbs.GetEnumerator();

If you want to keep a single mock variable to pass around, you can set it up like this.

var mockCommandBars = new Mock<CommandBars>();
mockCommandBars.Setup(cb => cb.GetEnumerator()).Returns(bars.GetEnumerator);
mockCommandBars.As<IEnumerable>().Setup(cb => cb.GetEnumerator()).Returns(bars.GetEnumerator);

This tells Moq that the Mock implements both interfaces, and defines GetEnumerator for both independently.

Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • 1
    Thank you so much! This actually saved my life ;) I already figured that it had something to do with the typing, but it would have taken me at least a 100 years to figure that one out... – Sven Amann May 27 '14 at 12:26
  • 1
    Also, note to self - if a method on a mock is ever returning null, first place to start is by enabling `MockBehavior.Strict` - saves much time :) – StuartLC May 27 '14 at 13:18