2010-04-12 2 views
1

RhinoMocks를 사용하여 특정 메소드를 호출 할 때 메소드가 아이템을 적절하게 그룹화 한 다음 다른 메소드를 호출하는지 확인하려고합니다. 이 같은매개 변수가 제대로 사용되고 있는지 확인하는 데 가장 좋은 테스트 패턴은 무엇입니까?

뭔가 : 문제가 나를 위해 시작되는 다음

//Arrange 
var bucketsOfFun = new BucketGame(); 

var balls = new List<IBall> 
       { 
        new Ball { Color = Color.Red }, 
        new Ball { Color = Color.Blue }, 
        new Ball { Color = Color.Yellow }, 
        new Ball { Color = Color.Orange }, 
        new Ball { Color = Color.Orange } 
       }; 

//Act 
bucketsOfFun.HaveFunWithBucketsAndBalls(balls); 

//Assert ??? 

이다. 내 방법은 다음과 같이하고있다 :

public void HaveFunWithBucketsAndBalls(IList<IBall> balls) 
{ 
    //group all the balls together according to color 
    var blueBalls = GetBlueBalls(balls); 
    var redBalls = GetRedBalls(balls); 
    // you get the idea 

    HaveFunWithABucketOfBalls(blueBalls); 
    HaveFunWithABucketOfBalls(redBalls); 
    // etc etc with all the different colors 
} 

public void HaveFunWithABucketOfBalls(IList<IBall> colorSpecificBalls) 
{ 
    //doing some stuff here that i don't care about 
    //for the test i'm writing right now 
} 

내가 주장하고 싶은 것은 그런 내가 다음 1 빨간 공의 그룹, 1 개 파란색 공을 전화 드렸습니다 HaveFunWithABucketOfBalls를 호출 할 때마다, 다음 1 노란색 공 , 오렌지 볼 2 개.

내가 그 행동을 주장 할 수 있다면 그 방법이 볼을 적절히 그룹화하고 싶은대로하고 있는지 확인할 수 있습니다.

가장 좋은 테스트 패턴은 무엇입니까?

+0

그냥 funsies 위해, 왜 당신의 방법은 다른 방법을 호출 테스트입니까? 아마도 여러분은 여러분의 객체에 대한 공용 메소드를 테스트하고 올바른 출력을 얻는다는 것을 주장해야하며 실제 내부 구현을 테스트해서는 안됩니다. – Juliet

+0

@Juliet 두 가지 방법이 모두 공개되어 있기 때문에 좋은 지적입니다. 내 실제 구현에서는 둘 다 독립적으로 사용할 수 있습니다. 그래서이 둘의 유일한 차이점은 여기에서 설명하는 방법으로 객체를 구성하는 방법입니다. 따라서이 기능을 테스트하고 싶습니다. – Joseph

답변

2

한 방법입니다 : 그런 경우입니다 가정하면, 어쩌면 이제

interface IBucketGame{ 
    void HaveFunWithBucketsAndBalls(IList<IBall> balls) 
    void HaveFunWithSpecificBalls(IList<IBall> balls) 
} 

당신은 상호 작용 테스트를 설정할 수 있습니다 의존성에 대한 색 특정 공으로 작업하는 것, 예를 들어, IBucketHandler :

//Arrange 
var bucketHandler = MockRepository.GenerateStub<IBuckerHandler>(); 
var bucketsOfFun = new BucketGame(bucketHandler); 
... 
//Assert 
bucketHandler.AssertWasCalled(x => x.HaveFunWithABucketOfBalls(redBalls)); 
bucketHandler.AssertWasCalled(x => x.HaveFunWithABucketOfBalls(greenBalls)); 

이 테스트에서는 BucketGame이 조롱 된 개체의 HaveFunWithABucketOfBalls을 올바르게 호출하는지 확인합니다. 이것은 여전히 ​​각 인수가 무엇인지 지정하는 데 어려움을 줄 수 있습니다. 새로운 종속성에 대한 정렬에 대한 책임을 강요함으로써 테스트를 더 쉽게 할 수 있습니다 (더 많은 추상화가 필요함). 그런 다음이 같은 끝낼 것 :

//Arrange 
var balls = new List<IBall>(); //Can really be anything, we just need the object reference 
var greenBalls = new List<IBall>(); 
var redBalls = new List<IBall>(); 
var sortedBalls = new [] { greenBalls, redBalls }; 

var bucketHandler = MockRepository.GenerateStub<IBucketHandler>(); 
var ballSorter = MockRepository.GenerateStub<IBallSorter>(); 
ballSorter.Stub(x => x.Sort(balls)).Return(sortedBalls); 

var bucketsOfFun = new BucketGame(bucketHandler, ballSorter); 

//Act 
bucketsOfFun.HaveFunWithBucketsAndBalls(balls); 

//Assert 
bucketHandler.AssertWasCalled(x => x.HaveFunWithABucketOfBalls(greenBalls)); 
bucketHandler.AssertWasCalled(x => x.HaveFunWithABucketOfBalls(redBalls)); 

그리고 BucketGame,이 시험을 통과 :

public BucketGame(IBucketHandler bucketHandler, IBallSorter ballSorter) 
{ 
    this.bucketHandler = bucketHandler; 
    this.ballSorter = ballSorter; 
} 

public void HaveFunWithBucketsAndBalls(IList<IBall> balls) 
{ 
    //group all the balls together according to color 
    var sortedBalls = ballSorter.Sort(balls); 
    foreach (var groupOfBalls in sortedBalls) 
    { 
     bucketHandler.HaveFunWithABucketOfBalls(groupOfBalls); 
    } 
} 

이것은 BucketGame 논리를 테스트합니다. IBallSorter 구현을위한 단위 테스트를 작성하여 필요에 따라 색상별로 볼을 정렬하는지 확인해야합니다. 이 테스트는 아마도 조롱을 필요로하지 않을 것입니다. 단순히 데이터를 넣을 수 있고 돌아 오는 데이터가 예상 한 것임을 주장 할 수 있습니다.

+0

데이비드에게 감사드립니다. 이것이 나를위한 최선의 접근법 일 것 같아요. 그리고 충분히 재미 있습니다. 제 구현의 실제 구현 유형은 이미 이와 비슷합니다. BucketHandler라고하는 추상화의 이름을 생각하면됩니다. – Joseph

+0

BucketHandler가 Stub이나 Mock이 될 것인가에 대한 질문입니다. 객체에 무언가가 완료되었다고 주장하고 있기 때문에, Stub이 아니라 Mock이되어야한다고 생각하게합니다.하지만 예제에서는 호출 중입니다. MockRepository.GenerateStub (); ? – Joseph

+0

@joseph - 이것을 스텁으로 만드는 것은 내가 습득 한 습관 일뿐입니다. 일반적으로 내 속성이 실제 속성 (예 : myStub.SomeProp = 10;)으로 작동하기 때문에 GenerateMock 을 거의 사용하지 않습니다. 이 경우 GenerateMock 으로 바꿀 수 있으며 여전히 작동하며 의미 상으로 정확합니다. –

0

테스트에서 가장 먼저해야 할 일은 테스트 대상이 정확히 무엇인지입니다. 그것은 무의미하게 들릴지 모르겠지만, 내 자신의 경험을 통해 상호 작용 테스트를 학습 할 때 이것이 혼란 스러울 수 있음을 안다.

나는 이것이 문제의 일부라고 생각하는 이유는 당신이 IBall 개체를 가지고 있지만 인터페이스의 일부로 보이지 않는 메서드에 대한 호출을 주장하려고한다는 것입니다. 아시다시피, Rhino는 인터페이스처럼 가상의 것을 무효화하여 마술입니다. 그래서 Rhino에 이것을 사용하려면 인터페이스를 제공해야합니다. 책임을 깰

[Test] 
public void HaveFunWithBucket_IfMoreThanOneColor_CallsHaveFunWithSpecificBallsForSpecificColor() 
    { 
     //Arrange 
     var bucketsOfFun = MockRepository.GenerateMock<IBucketGame>(); 

     IBall expColor_1 = new Ball(Color.Red); 
     IBall expColor_2 = new Ball(Color.Green); 
     IBall expColor_3 = new Ball(Color.Red); 
     var startlist = new List<IBall>{expColor_1, expColor_2, expColor_3}; 
     var onlyRedBalls = new List<IBall>{expColor_1, expColor_3}; 
     var onlyGreenBalls = new List<IBall>{expColor_2}; 

     //Act 
     bucketsOfFun.HaveFunWithBucketsAndBalls(balls); 

     //Assert 
     bucketsOfFun.AssertWasCalled(x=>x.HaveFunSpecificBalls(Arg<IEnumerable<IBall>>.List.Equal(onlyRedBalls))); 
     bucketsOfFun.AssertWasCalled(x=>x.HaveFunSpecificBalls(Arg<IEnumerable<IBall>>.List.Equal(onlyGreenBalls))); 

    } 

HTH,
Berryl이를 테스트

+0

@ Berryl 어떻게하면 buetsOfFun.HaveFunWithBucketsAndBalls (ball)을 호출하는 것이 실제로 아무것도 수행하는지 테스트 할 수 있습니다. 정의 된 구현이없는 인터페이스를 조롱했습니다. 구체적인 구현을 테스트하려고 했으므로, 내가 당신이 얻는 것을 잃어 버릴 정도입니다. – Joseph

+0

그것은 말도 안되는 테스트이지만 현재 스펙에서 요구하는 것입니다! 논리적 인 유스 케이스를 생각해 내기 시작할 수 있도록 Rhino의 메커니즘을보고 싶다고 가정했습니다. 논리적 인 유스 케이스를 생각해 볼 수 있습니다. – Berryl

+0

질문이 없습니다. 내가 갖고있는 실제 구현 문제. 실제로이 작업을 수행하려는 유스 케이스가 있으며 테스트 방법을 알 수 없습니다. 그래서 명확히하기 위해, 제 질문은 가설이 아니며, 제가 극복하고자하는 실제적인 것입니다. – Joseph

관련 문제