【问题标题】:How do I mock 'out' parameters with Machine.Fakes independently of the mock framework?如何独立于模拟框架使用 Machine.Fakes 模拟“输出”参数?
【发布时间】:2012-01-04 00:03:22
【问题描述】:

我在使用 Machine.Fakes 时陷入了僵局。我无法弄清楚如何使用 only Machine.Fakes 设备模拟 out 参数。由于 RhinoMocks 中的 a bug,我将我们的 mfakes 适配器切换到 FakeItEasy。据我所知,任何适配器都应该是可互换的。

问题是这导致“out”测试失败,看起来像这样的东西不再编译,因为Arg 是 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);

我尝试使用“虚拟”局部变量,将其设置为与原始 Arg&lt;T&gt; 参数设置的相同的值,但这导致我的测试失败 - 似乎该值没有通过! Arg&lt;T&gt; 确实有解决方案,但我不能再使用它了,因为它是 Rhino.Mocks 的一部分。

【问题讨论】:

    标签: c# unit-testing mocking rhino-mocks machine.fakes


    【解决方案1】:

    Machine.Fakes 无法处理这种情况。它根本没有实施。

    我个人不使用 out 参数,并且(如果我真的需要返回多个返回值)使用元组 (Tuple) 或自定义类用于此类场景。这就是为什么我从来没有把它放在首位。

    我还没有研究过,但在 Machine.Fakes 中实现对 ref 和 out 参数的处理可能是不可行的。在多个模拟框架之上实现包装器的挑战之一是,为了成功,所有模拟框架都需要在工作方式上有一个共同点。 Machine.Fakes 目前也不支持模拟事件,因为我无法找到所有这些事件的共同点(仅适用于两个 NSubstitute/FakeItEasy 与 Rhino/Moq)。

    在我看来,您目前有两种选择:

    1. 如果您控制我们所说的界面,您可以通过元组或自定义类绕过该问题。
    2. 如果您不拥有该接口,您始终可以在 Alexander Gross 建议的情况下恢复到底层模拟框架。

    很抱歉没有给你更好的答案;-)

    • 比约恩

    【讨论】:

      【解决方案2】:

      对于这种情况,您似乎需要直接使用 FakeItEasy。我认为问题在于 FakeItEasy 要求您通过将AssignsOutAndRefParameters 附加到假对象调用规范来设置out 参数的方式。不过这应该不是问题,因为 Machine.Fakes 所做的只是将 WhenToldTo 等转换为所使用的伪造框架的适当 API。

      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);
        }
      }
      

      【讨论】:

        【解决方案3】:

        从 1.7.0 版开始,Machine.Fakes 支持在假调用中设置 outref 参数 - 当使用 FakeItEasy 或 NSubstitute 适配器时。因此,您不必再直接使用 FakeItEasy。 Alex 的例子可以这样简化:

        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);
            }
        }
        

        【讨论】:

        • +1 表示更新。似乎这只适用于 void 方法?似乎有点限制,因为在很多情况下,out 参数被用于返回额外的返回值。
        • 是的,@MattDavey,我只为 void 方法实现了这个。我同意它的限制,但为查询实现它会使 API 变得复杂。
        • 此外,out 参数支持最初并未实现,因为它们被认为是糟糕的设计。我认为这是一个值得拥有的选项,因为即使是 .NET 框架也会使用 out 参数。但我不会说一个方法中的返回值和输出参数是好的设计。我会说要么返回一个元组,要么有多个输出参数。所以我以这种方式让 MFakes 固执己见。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-08
        • 2021-09-13
        • 1970-01-01
        相关资源
        最近更新 更多