1

我正在嘗試學習Rhino Mocks AAA語法,並且我無法斷言某個方法(使用任何參數值)被調用。我使用Machine.Specifications作爲我的測試框架。如何使用RhinoMocks AssertWasCalled使用三種不同類型的通用方法?

這種特殊的方法是通用的,我想確保它有三種不同的類型被稱爲三次。

repo.Save<T1>(anything), repo.Save<T2>(anything), and repo.Save<T3>(anything) 

我將每種類型的函數都存起來。但是我得到一個有趣的結果。 (下)

[Subject("Test")] 
public class When_something_happens_with_constraint 
{ 
    static IRepository repo; 
    static TestController controller; 
    static ActionResult result; 

    Establish context =() => 
    { 
     repo = MockRepository.GenerateMock<IRepository>(); 
     controller = new TestController(repo); 
     repo.Stub(o => o.Save<Something>(Arg<Something>.Is.Anything)); 
     repo.Stub(o => o.Save<SomethingElse>(Arg<SomethingElse>.Is.Anything)); 
     repo.Stub(o => o.Save<AnotherOne>(Arg<AnotherOne>.Is.Anything)); 
    }; 

    //post data to a controller 
    Because of =() => { result = controller.SaveAction(new SomethingModel() { Name = "test", Description = "test" }); }; 

    //controller constructs its own something using the data posted, then saves it. I want to make sure three calls were made. 
    It Should_save_something =() => repo.AssertWasCalled(o => o.Save<Somethign>(Arg<Something>.Is.Anything)); 
    It Should_save_something_else =() => repo.AssertWasCalled(o => o.Save<SomethingElse>(Arg<SomethingElse>.Is.Anything)); 
    It Should_save_another_one =() => repo.AssertWasCalled(o => o.Save<AnotherOne>(Arg<AnotherOne>.Is.Anything)); 
} 

結果是兩個例外和通過。

第一調用拋出:

System.InvalidOperationException:沒有期望是設置要被驗證,確保在該操作的方法調用是虛擬(C#)/可重寫(VB.Net)方法調用

第二個拋出:

System.InvalidOperationException:使用ARG僅在模擬方法調用,同時記錄。預期有1個參數,其中2個已被定義。

第三個通過...有些奇怪的原因。

我也嘗試使用GenerateMock()與期望在我的設置以及與存根使用GenerateStub()。兩者都以完全相同的結果結束。我必須做錯事。

我使用: MachineSpec 0.3.0.0和3.6.0.0 RhinoMocks

任何想法?

-----固定----------

下面是完整的(工作版本)與李的幫助。我正在使用一個額外的(非linq)圖層。我的實際問題是,我的一個測試在脫機實際代碼中重新使用了錯誤的lambda變量。 It Should_do_something =()=> repo.AssertWasCalled(o =>repo .Save(data)); // bad lambda

所以這裏有一個正確的測試參考樣本。

using System; 
using System.Linq; 
using System.Collections.Generic; 
using Machine.Specifications; 
using Rhino.Mocks; 

namespace OnlineTesting.Specifications 
{ 
    public interface Repository 
    { 
     void Save<T>(T data); 
     IQueryable<T> All<T>(); 
    } 

    public interface Service 
    { 
     void SaveItem(Item data); 
     void SaveAnotherItem(AnotherItem data); 
     void SaveOtherItem(OtherItem data); 
     List<Item> GetItems(); 
     List<AnotherItem> GetAnotherItems(); 
     List<OtherItem> GetOtherItems(); 
    } 

    public class ConcreteService : Service 
    { 
     Repository repo; 
     public ConcreteService(Repository repo) 
     { 
      this.repo = repo; 
     } 
     public void SaveItem(Item data) 
     { 
      repo.Save(data); 
     } 
     public void SaveAnotherItem(AnotherItem data) 
     { 
      repo.Save(data); 
     } 
     public void SaveOtherItem(OtherItem data) 
     { 
      repo.Save(data); 
     } 

     public List<Item> GetItems() 
     { 
      return repo.All<Item>().ToList(); 
     } 
     public List<AnotherItem> GetAnotherItems() 
     { 
      return repo.All<AnotherItem>().ToList(); 
     } 
     public List<OtherItem> GetOtherItems() 
     { 
      return repo.All<OtherItem>().ToList(); 
     } 
    } 

    public class Item 
    { 
     public int Id { get; set; } 
    } 
    public class OtherItem 
    { 
    } 
    public class AnotherItem 
    { 
    } 


    public class When_something_else_happens 
    { 
     Establish context =() => 
     { 
      _repository = MockRepository.GenerateMock<Repository>(); 
      _service = new ConcreteService(_repository); 
      _controller = new TestController(_service); 

      _repository.Stub(o => o.Save<Item>(Arg<Item>.Is.Anything)).WhenCalled(
       new Action<MethodInvocation>((o) => 
       { 
        var data = o.Arguments.FirstOrDefault() as Item; 
        if (data != null && data.Id == 0) 
         data.Id++; 
       })); 
     }; 

     Because of =() => _controller.DoSomethingElse(); 

     It should_save_the_first_thing =() => 
      _repository.AssertWasCalled(repo => repo.Save(Arg<Item>.Is.Anything)); 

     It should_save_the_other_thing =() => 
      _repository.AssertWasCalled(repo => repo.Save(Arg<OtherItem>.Is.Anything)); 

     It should_save_the_last_thing =() => 
      _repository.AssertWasCalled(repo => repo.Save(Arg<AnotherItem>.Is.Anything)); 

     static Repository _repository; 
     static TestController _controller; 
     static Service _service; 
    } 

    public class TestController 
    { 
     readonly Service _service; 

     public TestController(Service service) 
     { 
      _service = service; 
     } 

     public void DoSomethingElse() 
     { 
      _service.SaveItem(new Item()); 
      _service.SaveOtherItem(new OtherItem()); 
      _service.SaveAnotherItem(new AnotherItem()); 
     } 
    } 
} 
+0

另外...我不能在調用之前設置參數,因爲控制器操作會構造一個新對象並將其傳遞給存儲庫。所以我使用Arg 。任何事情。我只是想確保repo.save被稱爲特定類型。 – Nathan 2010-11-19 16:01:34

回答

0

試試看。

[Subject("Test")] 
public class When_something_happens_with_constraint 
{ 
    static IRepository repo; 
    static TestController controller; 
    static ActionResult result; 

    Establish context =() => 
    { 
     repo = MockRepository.GenerateMock<IRepository>(); 
     controller = new TestController(repo); 
    }; 

    //post data to a controller 
    Because of =() => result = controller.SaveAction(new SomethingModel() { Name = "test", Description = "test" }); 

    //controller constructs its own something using the data posted, then saves it. I want to make sure three calls were made. 
    It Should_save_something =() => repo.AssertWasCalled(o => o.Save(Arg<Something>.Is.Anything)); 
    It Should_save_something_else =() => repo.AssertWasCalled(o => o.Save(Arg<SomethingElse>.Is.Anything)); 
    It Should_save_another_one =() => repo.AssertWasCalled(o => o.Save(Arg<AnotherOne>.Is.Anything)); 
} 
+0

我甚至可能會創建一個模塊級別的SomethingModel,以便您可以驗證它實際上是發送到存儲庫進行保存的模塊級別。 – leebrandt 2010-11-19 16:33:49

+0

謝謝李。經過測試和比較,我發現了問題。我發佈了上面的完整結果。 – Nathan 2010-11-19 17:16:03

1

,每個人都似乎被粉飾的一點是,你不需要爲了執行「斷言被稱爲」存根。而且,你寫的方式,Arg<T>.Is.Anything,它會忽略這個類型。您不驗證任何通用約束。你想使用Arg<T>.Is.TypeOf<T>。檢查documentation瞭解更多詳情。

----------------------------------------------- 
| Arg<T>.Is |        | 
=============================================== 
| Anything() | No constraints    | 
----------------------------------------------- 
| TypeOf<T>() | Argument is of a certain type | 
----------------------------------------------- 

固定代碼片段仍然是太複雜了。您沒有使用「保存時」保存的data對象。你不需要它做一個簡單的「斷言被稱爲」。

@ leebrandt的代碼看起來正確和簡單,因爲它沒有引入automocking容器。

相關問題