Question

I've hit an impasse with Machine.Fakes. I cannot figure out how to mock an out parameter using only Machine.Fakes equipment. Because of a bug in RhinoMocks, I switched our mfakes adapter to FakeItEasy. As far as I can tell, any of the adapters should be interchangable.

The problem is that this caused the "out" tests to fail, things that looked like this no longer compile, because Arg was Rhino.Mocks.

The<IMembershipService>()
    .WhenToldTo(x => x.CreateUser(Param<string>.IsAnything,
        Param<bool>.IsAnything,
        Param<object>.IsAnything, 
        out Arg<MembershipCreateStatus>
            .Out(MembershipCreateStatus.UserRejected)
            .Dummy))
    .Return(user);

I tried using a "dummy" local variable, set to the same value the original Arg<T> param set it to, but this has caused my tests to fail -- it seems as though the value isn't being passed through! Arg<T> really had the solution, but I can't use it anymore, as it's part of Rhino.Mocks.

Was it helpful?

Solution

Since version 1.7.0 Machine.Fakes supports setting up out and ref parameters in fake calls - when using the FakeItEasy or NSubstitute adapters. Thus, you don't have to use FakeItEasy directly any more. Alex' example can be simplified like this:

using Machine.Fakes;
using Machine.Specifications;

namespace MSpecMFakesOutParam
{
    public interface IFoo
    {
        void Foo(out int foo);
    }

    public class When_using_FakeItEasy_with_out_params : WithFakes
    {
        static int Out;

        Establish context = () =>
        {
            int ignored;
            The<IFoo>().WhenToldTo(x => x.Foo(out ignored)).AssignOutAndRefParameters(42);
        };

        Because of = () => The<IFoo>().Foo(out Out);

        It should_assign_the_out_param = () => Out.ShouldEqual(42);
    }
}

OTHER TIPS

Machine.Fakes doesn't handle this scenario. It's simply not implemented.

I personally don't use out parameters and (if I really need to return multiple return values) use a tuple (Tuple<T,K>) or custom class for such scenarios. That's why it never was really high on my priority.

I haven't looked into it, but it might be possible that implementing handling of ref and out parameters in Machine.Fakes isn't feasible. One of the challenges of implementing a wrapper on top of several mocking frameworks is that in order to succeed, all mocking frameworks need to have a common denominator in how they work. Machine.Fakes also doesn't support mocking events right now because I wasn't able to find the common denominator for all of them (only for two NSubstitute/FakeItEasy vs Rhino/Moq).

As I see it you got currently two options:

  1. If you control the interface we're talking about, you can bypass the problem via a tuple or custom class.
  2. If you don't own the interface you can always revert to the underlying mock framework for such cases as Alexander Gross suggested.

Sorry for not giving you a better answer ;-)

  • Bjoern

It seems like for this case you need to use FakeItEasy directly. I think the problem lies in the way how FakeItEasy requires you to set up out parameters by appending AssignsOutAndRefParameters to the fake object call specification. That shouldn't be a problem though since all that Machine.Fakes does is translate WhenToldTo etc. to the appropriate API of the faking framework used.

using FakeItEasy;

using Machine.Fakes;
using Machine.Specifications;

namespace MSpecMFakesOutParam
{
  public interface IFoo
  {
    void Foo(out int foo);
  }

  public class When_using_FakeItEasy_with_out_params : WithFakes
  {
    static IFoo Foo;
    static int Out;

    Establish context = () =>
    {
      Foo = An<IFoo>();

      var ignored = A<int>.Ignored;
      A.CallTo(() => Foo.Foo(out ignored)).AssignsOutAndRefParameters(42);
    };

    Because of = () => Foo.Foo(out Out);

    It should_assign_the_out_param =
      () => Out.ShouldEqual(42);
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top