2013-10-31 63 views
2

我試圖測試一些我已經寫入的代碼試圖嘲笑使用Machine.Fakes(它使用引擎蓋下的Moq)的func的問題。有關示例,請參閱下面的代碼。如何使用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在那裏方法如下:

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

現在我得到這個錯誤

對象實例不是由Moq創建的。
參數名稱:嘲諷

任何想法?

編輯

於是,我試着寫另一個測試不machine.fakes,按Mocking methods with Expression<Func<T,bool>> parameter using Moq。原來這是一個明顯的問題。在現實RoutingEngine使用的func被未被嘲笑

The<IMessageRouters>() 
    .WhenToldTo(x => x.Where(router => router.CanRoute(Param.IsAny<ProcessSkuCostUpdated>()))) 
    .Return(new List<IMessageRouter> {Router}); 

上述對無軸承凡在運行時被執行,並作爲func被編譯成在編譯時的私有方法是不可能的。似乎喜歡模擬func,我需要將它推到一個界面。聞起來,因爲我只是爲了測試而推動內部行爲。

回答

1

我看到兩個問題與你的測試代碼:

  1. 您使用上IMessageRouters建立Where()調用的表情太露骨。它不應該關心什麼確切的功能通過。
  2. 您正在驗證Subject上是否調用了Route()。相反,您應該驗證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; 
} 
1

我看到一種避免嘲笑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-was-called(或者看起來在Moq中)。

相關問題