我正在尝试测试我编写的一些代码,这些代码遇到了一些问题,试图使用Machine.Fakes (它在幕后使用Moq )来模拟func。有关示例,请参阅下面的代码。
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);
}
}
测试就在这里
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方法更改为:
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没有被模仿。
The<IMessageRouters>()
.WhenToldTo(x => x.Where(router => router.CanRoute(Param.IsAny<ProcessSkuCostUpdated>())))
.Return(new List<IMessageRouter> {Router});
上面的内容对运行时执行的位置没有影响,也不能在编译时将func编译到私有方法中。好像是在嘲笑这个功能,我需要把它推到一个界面上。尽管我只是为了测试而提高内部行为的气味。
发布于 2013-11-01 07:14:50
我发现您的测试代码有两个问题:
Where()
上设置IMessageRouters
调用的表达式太明确了。它不应该关心传递了什么确切的功能。Route()
上调用了Subject
。相反,您应该验证Message
是否已传递给IMessageRouter
。作为一个额外的改进,您可以省略Router
字段并直接使用The<IMessageRouter>()
。
[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;
}
发布于 2013-10-31 17:19:11
我发现了一种完全避免嘲笑Func<>
的方法。我希望您会感兴趣:)为什么不忘记广义的Where(Func<>)
方法并提供特定的查询方法。您拥有入站消息和路由器。
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<>
)。
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
检查就可以了,比如
public IEnumerable<IMessageRouter> For<T>() { ... }
和
var messageRouters = _messageRouters.For<T>();
您现在不需要模拟任何Func<>
,您只需执行一个assert调用(或者在Moq中看起来是这样)。
https://stackoverflow.com/questions/19707931
复制相似问题