1

Rhino Mocks AAA 구문을 배우려고하는데 특정 메서드 (인수 값 포함)가 호출되었음을 증명하는 데 문제가 있습니다. 내 테스트 프레임 워크로 Machine.Specifications를 사용하고 있습니다.RhinoMock을 사용하여 세 가지 유형의 일반 메서드를 AssertWasCalled하는 방법은 무엇입니까?

이 특별한 방법은 일반적이므로 3 가지 유형으로 세 번 호출했는지 확인하고 싶습니다.

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 및 RhinoMocks 3.6.0.0

어떤 아이디어?

----- 여기에 이명박의 도움으로 전체 (작업 버전)의 고정 ----------

. 여분의 (non-linq) 레이어를 사용하고 있습니다. 내 실제 문제는 내 테스트 중 하나가 오프라인 실제 코드에서 잘못된 람다 변수를 다시 사용한다는 것이 었습니다. It Should_do_something =() => repo.AssertWasCalled (o =>repo. 저장 (데이터)); // 나쁜 람다

그래서 여기에 올바른 테스트를위한 샘플이 있습니다.

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

답변

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

+0

고마워요. 당신의 것을 시험하고 그것을 광산과 비교 한 후에 나는 그 문제를 발견했다. 위의 전체 결과를 게시했습니다. – Nathan

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 개체를 사용하고 있지 않습니다. 그리고 당신은 간단한 "assert가 호출되었다"고 할 필요가 없습니다.

@ leebrandt의 코드는 automocking 컨테이너를 도입하지 않고도 정확하고 간단하게 보입니다.