C# 如何模拟函数<&燃气轮机;使用机器。假货(最低起订量)?

C# 如何模拟函数<&燃气轮机;使用机器。假货(最低起订量)?,c#,moq,mspec,machine.fakes,C#,Moq,Mspec,Machine.fakes,我正在测试我编写的一些代码,这些代码遇到了使用Machine.Fakes(在引擎盖下使用Moq)模拟func的问题。有关示例,请参见下面的代码 公共类路由引擎:IRoutingEngine { 专用只读IMessageRouters(消息路由器); 公共路由引擎(IMessageRouters messageRouters) { _消息路由器=消息路由器; } 公共无效路线(T入站) { var messageRouters=_messageRouters.Where(x=>x.CanRoute

我正在测试我编写的一些代码,这些代码遇到了使用Machine.Fakes(在引擎盖下使用Moq)模拟func的问题。有关示例,请参见下面的代码

公共类路由引擎:IRoutingEngine
{
专用只读IMessageRouters(消息路由器);
公共路由引擎(IMessageRouters messageRouters)
{
_消息路由器=消息路由器;
}
公共无效路线(T入站)
{
var messageRouters=_messageRouters.Where(x=>x.CanRoute(inbound));
foreach(messageRouters中的var路由器)
路由(入站);
}
}
公共类消息路由器:IMessageRouters
{
公共IList_路由器=新列表();
公共IEnumerable其中(Func Func)
{
返回_.Where(func);
}
公共无效添加(IMessageRouter消息路由器)
{
_添加(messageRouter);
}
}
测试就在这里

public类,当使用\u fakes路由\u消息时:with subject
{
确定=()=>
{
Message=newmymessage{SomeValue=1,SomeOtherValue=11010};
路由器=路由器();
Router.WhenToldTo(x=>x.CanRoute(Message)).Return(true);
().WhenToldTo(x=>x.Where(router=>router.CanRoute(Message)).Return(新列表{router});
};
因为=()=>Subject.Route(消息);
它应该路由消息=()=>Subject.WasToldTo(x=>x.route(Param.IsAny());
静态MyMessage消息;
静态IMessageRouter;
}
我得到了一个不受支持的表达式,因此我将
IMessageRouters
上的where方法更改为:

public IEnumerable其中(Expression func)
{
返回_.Where(func.Compile());
}
现在我得到了这个错误

对象实例不是由Moq创建的。
参数名称:mocked

有什么想法吗

编辑

所以我试着在没有机器的情况下编写另一个测试。事实证明这是一个明显的问题。真实RoutingEngine中使用的func没有被嘲笑

The()
.WhenToldTo(x=>x.Where(router=>router.CanRoute(Param.IsAny()))
.Return(新列表{Router});

以上内容与运行时执行的Where无关,并且不能在编译时将func编译为私有方法。好像是在模仿func,我需要把它推到一个接口上。闻起来就像我纯粹为了测试而提升内在行为

我找到了一种避免嘲笑
Func
的方法。我希望您对此感兴趣:)为什么不忘记广义的
Where(Func)
方法,并提供具体的查询方法呢。您拥有入站邮件和路由器

var messageRouters=_messageRouters.For();

您现在不必模拟任何
Func
s,只需执行一个调用了assert(或以Moq中的方式)的操作即可。

我发现您的测试代码存在两个问题:

  • 用于设置
    IMessageRouters
    上的
    Where()
    调用的表达式过于明确。它不应该关心传递的确切函数
  • 您正在验证是否对
    主题
    调用了
    Route()
    。相反,您应该验证
    消息
    是否已传递到
    IMessageRouter
  • 作为另一项改进,您可以省略
    路由器
    字段,直接使用
    the()

    [Subject(typeof(RoutingEngine))]
    public class when_routing_a_message_with_fakes : WithSubject<RoutingEngine>
    {
        Establish that = () =>
        {
            Message = new MyMessage { SomeValue = 1, SomeOtherValue = 11010 };
            The<IMessageRouter>().WhenToldTo(x => x.CanRoute(Message)).Return(true);
            The<IMessageRouters>().WhenToldTo(x => x.Where(Param<Func<IMessageRouter, bool>>.IsAnything))
                .Return(new List<IMessageRouter> { The<IMessageRouter>() });
        };
    
        Because of = () => Subject.Route(Message);
    
        It should_route_the_message = () =>
            The<IMessageRouter>().WasToldTo(x => x.Route(Message));
    
        static MyMessage Message;
    }
    
    [主题(类型(路由引擎))]
    使用伪邮件路由邮件时的公共类:with subject
    {
    确定=()=>
    {
    Message=newmymessage{SomeValue=1,SomeOtherValue=11010};
    ().WhenToldTo(x=>x.CanRoute(Message)).Return(true);
    ().WhenToldTo(x=>x.Where(Param.IsAnything))
    .Return(新列表{The()});
    };
    因为=()=>Subject.Route(消息);
    它应该路由消息=()=>
    ().WasToldTo(x=>x.Route(Message));
    静态MyMessage消息;
    }
    
    public class RoutingEngine : IRoutingEngine
    {
        private readonly IMessageRouters _messageRouters; 
    
        public RoutingEngine(IMessageRouters messageRouters)
        {
            _messageRouters = messageRouters; 
        }
    
        public void Route<T>(T inbound)
        {
            var messageRouters = _messageRouters.For(inbound); 
            foreach(var router in messageRouters)
                router.Route(inbound); 
        }
    }
    
    public IEnumerable<IMessageRouter> For<T>() { ... }
    
    var messageRouters = _messageRouters.For<T>();
    
    [Subject(typeof(RoutingEngine))]
    public class when_routing_a_message_with_fakes : WithSubject<RoutingEngine>
    {
        Establish that = () =>
        {
            Message = new MyMessage { SomeValue = 1, SomeOtherValue = 11010 };
            The<IMessageRouter>().WhenToldTo(x => x.CanRoute(Message)).Return(true);
            The<IMessageRouters>().WhenToldTo(x => x.Where(Param<Func<IMessageRouter, bool>>.IsAnything))
                .Return(new List<IMessageRouter> { The<IMessageRouter>() });
        };
    
        Because of = () => Subject.Route(Message);
    
        It should_route_the_message = () =>
            The<IMessageRouter>().WasToldTo(x => x.Route(Message));
    
        static MyMessage Message;
    }