Каков наилучший шаблон тестирования для проверки правильности использования параметров? - PullRequest
1 голос
/ 12 апреля 2010

Я использую Rhino Mocks, чтобы проверить, что при вызове определенного метода этот метод, в свою очередь, будет правильно группировать элементы, а затем вызывать другой метод.

Примерно так:

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

Я хочу сказать, что каждый раз, когда я вызываю HaveFunWithABucketOfBalls, я называю его группой из 1 красного шара, затем 1 синего шара, затем 1 желтого шара, затем 2 оранжевых шара.

Если я могу утверждать это поведение, то я могу убедиться, что метод выполняет то, что я хочу, то есть правильно группирует шары.

Есть какие-нибудь идеи о том, какой будет наилучший шаблон тестирования для этого?

Ответы [ 2 ]

2 голосов
/ 13 апреля 2010

Один из способов проверить это - снять ответственность за работу с шариками, зависящими от цвета, до зависимости, скажем, 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 голосов
/ 13 апреля 2010

первое, что вам нужно разобраться в любом тесте, это то, что именно ваш предмет под тестом. это может показаться необоснованным, но я знаю по собственному опыту, что это может сбивать с толку, когда вы изучаете тестирование взаимодействия.

причина, по которой я предполагаю, что это является частью проблемы, заключается в том, что у вас есть объект IBall, но вы хотите подтверждать вызовы, сделанные для метода, который не является частью интерфейса. Как вы знаете, Rhino творит чудеса, переопределяя что-то виртуальное, например интерфейс; так что если вы хотите использовать Rhino для этого, вы должны предоставить ему интерфейс. Если предположить, что это так, может быть,

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

Теперь вы можете настроить интерактивный тест:

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

    }

НТН,
Berryl

...