首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用Func<> (Moq)来模拟Machine.Fakes?

如何使用Func<> (Moq)来模拟Machine.Fakes?
EN

Stack Overflow用户
提问于 2013-10-31 13:33:19
回答 2查看 1.4K关注 0票数 2

我正在尝试测试我编写的一些代码,这些代码遇到了一些问题,试图使用Machine.Fakes (它在幕后使用Moq )来模拟func。有关示例,请参阅下面的代码。

代码语言:javascript
运行
复制
public class RoutingEngine : IRoutingEngine
{
    private readonly IMessageRouters _messageRouters; 

    public RoutingEngine(IMessageRouters messageRouters)
    {
        _messageRouters = messageRouters; 
    }

    public void Route<T>(T inbound)
    {
        var messageRouters = _messageRouters.Where(x => x.CanRoute(inbound)); 
        foreach(var router in messageRouters)
            router.Route(inbound); 
    }
}

public class MessageRouters : IMessageRouters
{
    public IList<IMessageRouter> _routers = new List<IMessageRouter>();

    public IEnumerable<IMessageRouter> Where(Func<IMessageRouter, bool> func)
    {
        return _routers.Where(func); 
    }

    public void Add(IMessageRouter messageRouter)
    {
        _routers.Add(messageRouter); 
    }
}

测试就在这里

代码语言:javascript
运行
复制
public class when_routing_a_message_with_fakes : WithSubject<RoutingEngine>
{
    Establish that = () =>
    {
        Message = new MyMessage{ SomeValue= 1, SomeOtherValue = 11010 };
        Router = The<IMessageRouter>();
        Router.WhenToldTo(x => x.CanRoute(Message)).Return(true);             
        The<IMessageRouters>().WhenToldTo(x => x.Where(router => router.CanRoute(Message))).Return(new List<IMessageRouter> { Router }); 
    };

    Because of = () => Subject.Route(Message);

    It should_do_route_the_message = () => Subject.WasToldTo(x => x.Route(Param.IsAny<MyMessage>()));

    static MyMessage Message;
    static IMessageRouter Router;
}

我得到了上述不受支持的表达式,因此我将IMessageRouters上的where方法更改为:

代码语言:javascript
运行
复制
public IEnumerable<IMessageRouter> Where(Expression<Func<IMessageRouter, bool>> func)
{
    return _routers.Where(func.Compile()); 
}

现在我明白了这个错误

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

有什么想法吗?

编辑

因此,我尝试在没有machine.fakes的情况下编写另一个测试,如Mocking methods with Expression> parameter using Moq所示。原来这是个明显的问题。在实际的RoutingEngine中使用的func没有被模仿。

代码语言:javascript
运行
复制
The<IMessageRouters>()
    .WhenToldTo(x => x.Where(router => router.CanRoute(Param.IsAny<ProcessSkuCostUpdated>())))
    .Return(new List<IMessageRouter> {Router});

上面的内容对运行时执行的位置没有影响,也不能在编译时将func编译到私有方法中。好像是在嘲笑这个功能,我需要把它推到一个界面上。尽管我只是为了测试而提高内部行为的气味。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-11-01 07:14:50

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

  1. 用于在Where()上设置IMessageRouters调用的表达式太明确了。它不应该关心传递了什么确切的功能。
  2. 您正在验证是否在Route()上调用了Subject。相反,您应该验证Message是否已传递给IMessageRouter

作为一个额外的改进,您可以省略Router字段并直接使用The<IMessageRouter>()

代码语言:javascript
运行
复制
[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;
}
票数 1
EN

Stack Overflow用户

发布于 2013-10-31 17:19:11

我发现了一种完全避免嘲笑Func<>的方法。我希望您会感兴趣:)为什么不忘记广义的Where(Func<>)方法并提供特定的查询方法。您拥有入站消息和路由器。

代码语言:javascript
运行
复制
public class MessageRouters : IMessageRouters
{
    public IList<IMessageRouter> _routers = new List<IMessageRouter>();

    public IEnumerable<IMessageRouter> For<T>(T inbound)
    {
        return _routers.Where(x => x.CanRoute(inbound)); 
    }

    public void Add(IMessageRouter messageRouter)
    {
        _routers.Add(messageRouter); 
    }
}

测试中的类变得更简单(在签名中,没有Func<>)。

代码语言:javascript
运行
复制
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); 
    }
}

我猜您也不需要检查入站消息的实际实例,也许您只需进行一次Type检查就可以了,比如

代码语言:javascript
运行
复制
public IEnumerable<IMessageRouter> For<T>() { ... }

代码语言:javascript
运行
复制
var messageRouters = _messageRouters.For<T>();

您现在不需要模拟任何Func<>,您只需执行一个assert调用(或者在Moq中看起来是这样)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19707931

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档