2012-01-03 51 views
1

我有下面的示例測試代碼如何從一個存根根據拉姆達參數返回不同的值

public Stage Test(Stage Stage) 
    { 
     var StartStage = StageRepository.Single(x => x.Order == 1); 
     var EndStage = StageRepository.Single(x => x.Order == 5); 
     var ErrorStage = StageRepository.Single(x => x.Name == "Error"); 

     if (Stage == StartStage) 
     { 
      return EndStage; 
     } 
     else 
     { 
      return ErrorStage; 
     } 
    } 

,我試圖用下面的單元測試

[TestMethod] 
    public void XXXTest() 
    { 
     //// Arrange 
     var AutoMocker = new RhinoAutoMocker<StageService>(MockMode.AAA); 

     MockRepository mockRepository = new MockRepository(); 

     var MockStageRepository = AutoMocker.Get<IRepository<Stage>>(); 

     Stage StartStage = mockRepository.Stub<Stage>(); 
     StartStage.Order = 1; 

     Stage EndStage = mockRepository.Stub<Stage>(); 
     EndStage.Order = 5; 

     Stage ErrorStage = mockRepository.Stub<Stage>(); 
     ErrorStage.Name = "Error"; 

     System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> StartParam = x => x.Order == 1; 
     MockStageRepository 
      .Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(StartParam))) 
      .Return(StartStage); 

     System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> EndParam = x => x.Order == 1; 
     MockStageRepository 
      .Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(EndParam))) 
      .Return(EndStage); 

     System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> ErrorParam = x => x.Order == 1; 
     MockStageRepository 
      .Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(ErrorParam))) 
      .Return(ErrorStage); 

     StageService StageService = AutoMocker.ClassUnderTest; 


     //Act 
     var ReturnStage = StageService.Test(StartStage); 


     //Assert 
     Assert.AreEqual(ReturnStage, EndStage); 
    } 
進行測試

但是,這不起作用,因爲它在調用StageRepository.Single()時不會返回任何內容。如果我更改存根代碼以忽略參數,那麼它會返回一些內容,但它將是每次調用Single()時返回的同一個對象,我不想這樣做。

是否有可能以這種方式配置RhinoMocks,以便根據傳入它的lambda從存根中返回不同的對象?

+0

對不起什麼是'RhinoAutoMocker'? – sll 2012-01-03 17:07:43

+0

'RhinoAutoMocker'是StructureMap的一部分,只是創建了簡單的測試對象及其所有依賴項,供您嘲笑。 – 2012-01-03 17:28:06

+0

邁克 - 這只是一個錯字,第二個設置行也返回StartStage而不是EndStage? – 2012-01-03 17:41:23

回答

2

我認爲你的問題的根源在於Expression<Func<T,U>>類型上的平等是通過引用而非價值來執行的。這意味着你告訴Rhino Mocks尋找在測試中創建的表達式的實例,而不是在測試代碼中創建的表達式。

兩種可能的方法來記:

  • 之一將是提供一種方式來傳遞對從試驗階段類的lambda表達式,這樣當參數檢查發生他們對工作相同的實例。

    也許是這樣的:設立時

    internal void SetStartStage(Expression<Func<Entities.Stage,bool>> predicate) 
    { 
        ... 
    } 
    

    的這種逆也將工作,即提供Expression對象爲可通過你的測試訪問字段/屬性,然後用你的那些模擬:

    internal Expression<Func<Entities.State,bool>> StartStagePredicate 
    { 
        get{ return x => x.Order == 1; } 
    } 
    
  • 另一種選擇是爲使用ArgsMatches方法以查看是否正確參數檢查Stage對象的狀態。這需要建立在您的測試一些Stage對象將匹配條件:

    var startStageTester = new Stage { Order = 1 }; 
    MockStageRepository 
         .Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Matches(y => y.Compile()(startStageTester))) 
         .Return(StartStage); 
    

    Compile()的調用是有點刺耳,但因爲你正在處理的表達,而不是直線上升的λ,你我們必須編譯它才能評估它。現在

    ,如果Stage的東西是很難創造,那麼你可能需要創建一個的模擬/存根(或使用你StartStage),並把它從Order屬性返回1(的情況下無論如何都是StartStage)。

可能還有其他一些我現在還沒有想過的。

0

謝謝。這很有用。我遺漏的一件事是ExpressionTree上的Compile方法。示例代碼中存在一個小錯誤(您使用x兩次)。爲了完整,這裏是工作代碼。

 MockStageRepository2 
      .Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Matches(y => y.Compile()(StartStage2)))) 
      .Return(StartStage2); 
+0

ooo ...對不起。我已經更新了示例。 – ckramer 2012-01-04 17:21:35

1

IF LINQ的條件並不重要,我建議與之相匹配的爲已任,像這樣

repository.Stub(x => x.Find(Arg<System.Linq.Expressions.Expression<Func<Entity, bool>>>.Is.Anything)).Return(entitiesList.AsQueryable()); 

希望這有助於。