views:

51

answers:

2

I'm using Rhino Mocks to try to verify that when I call a certain method, that the method in turn will properly group items and then call another method.

Something like this:

//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 ???

Here is where the trouble begins for me. My method is doing something like this:

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
}

What I want to assert is that each time I call HaveFunWithABucketOfBalls that I'm calling it with a group of 1 red ball, then 1 blue ball, then 1 yellow ball, then 2 orange balls.

If I can assert that behavior then I can verify that the method is doing what I want it to do, which is grouping the balls properly.

Any ideas of what the best testing pattern for this would be?

A: 

hi joeseph

the first thing you need to sort out in any test is what exactly your Subject Under Test is. that might sound gratuitous but I know from my own experiences that this can be confusing when you are learning interaction testing.

the reason I am guessing this is part of the problem is that you have an IBall object, but you want to asserts calls being made on a method that doesn't appear to be part of an interface. As you know, Rhino does it's magic by overriding something virtual, like an interface; so if you want to use to Rhino to do this you have to give it an interface. Assuming that is the case, maybe

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

Now you can set up an interaction test:

[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

Berryl
@Berryl How are you testing, then, that calling bucketsOfFun.HaveFunWithBucketsAndBalls(balls) actually does anything at all. You just mocked an interface, which has no defined implementation. I was trying to test a concrete implementation, so I'm kind of losing you on what you're getting at there.
Joseph
it is a nonsense test, but that is what your current specification calls for! I assumed you just wanted to get see some of the mechanics of Rhino so you can start to think out a logical use case, which will lead to a logical test...
Berryl
@Berryl No the question I'm asking is just a proxy to a real implementation problem that I'm having. I actually do have a use case for wanting to do this, and I can't figure out the way to test it. So to clarify, my question is not a hypothetical, it's an actual thing that I'm trying to overcome.
Joseph
+2  A: 

One way to test this is to break out the responsibility of working with a colour-specific balls to a dependency, say, 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));

This test is then checking your BucketGame correctly calls HaveFunWithABucketOfBalls on the mocked object. This may still give you trouble in specifying what each argument should be. You can in turn make this easier to test (at the expense of introducing more abstraction) by pushing the responsibility for sorting the balls to a new dependency. You'd then end up with something like this:

//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));

And to pass this test, in 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);
    }
}

This tests the BucketGame logic. You'll now want to write unit tests for an IBallSorter implementation to check that it sorts the balls by colour as you require. Those tests probably won't need any mocking, you'll simply be able to throw data in and assert that the data you get back is what you expect.

David Tchepak
Thanks David. I think this might be the best approach for me. And funny enough, my real implementation kind of resembles this construction already, I just need to think of a name for the abstraction that you termed BucketHandler.
Joseph
One question, should the BucketHandler be a Stub or a Mock, because you're asserting that the object had something done to it, which makes me think it should be a Mock, not a Stub, but in your example you're calling MockRepository.GenerateStub<IBucketHandler>(); ?
Joseph
@joseph - making this a stub is just a habit I've gotten into. I almost never use GenerateMock<T> because I generally want my properties to work as real properties (e.g. myStub.SomeProp = 10;). In this case you can replace it with GenerateMock<T> and it will still work, and is probably more semantically correct.
David Tchepak