Как настроить mocked-значения для защищенных методов с помощью moq? - PullRequest
0 голосов
/ 11 апреля 2011

Например, возьмем следующий класс:

class GameBoard    
{
    public double Evaluate(PieceType cpusPieceType)
    {
        ...
        for (var i = 0; i < _tableRepository.Size; ++i)
            for (var j = 0; j < _tableRepository.Size; ++j)
                 if (_tableRepository [i, j] != PieceType.Empty)
                 {
                     var isMax = _tableRepository [i, j] == cpusPieceType;

                     var value = EvaluatePosition (i, j, _tableRepository [i, j]);
                     ...
                 }
        ...
    }

    protected virtual double EvaluatePosition (int row, int column, PieceType pieceType)
    { ... }
}

Я хотел бы написать тест для функции Evaluate, но это, в свою очередь, зависит от значений, возвращаемых функцией EvaluatePosition, которая объявлена ​​защищенной.Теперь моя идея заключалась в том, что я мог бы использовать такой класс:

class XGameBoard : GameBoard
{
    protected override double EvaluatePosition (int row, int column, PieceType pieceType)
    {
        // this will call EvaluatePosition_ShouldReturn which will be mocked and have a value previously set up
        return EvaluatePosition_ShouldReturn (row, column, pieceType);
    }
    public virtual double EvaluatePosition_ShouldReturn (int row, int column, PieceType pieceType)
    {
        return base.EvaluatePosition (row, column, pieceType);
    } 
}

Тест будет выглядеть так:

_gameBoardMock = new Mock<XGameBoard>(...);

for (var i = 4; i < _size - 4; i += 2)
    for (var j = 4; j < _size - 4; j += 2)
        _gameBoardMock.Setup (x => x.EvaluatePosition_ShouldReturn (i, j, PieceType.Cross)).Returns (1.0);

var result = _gameBoardMock.Object.Evaluate (PieceType.Cross);

Проблема в том, что EvaluatePosition внутри функции Evaluate всегда возвращает 0и не вызывается переопределенная функция, которая должна возвращать значение, которое было установлено.

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 13 апреля 2011

Я хотел бы прояснить проблему немного подробнее. Ситуация в том, что функция Evaluate должна возвращать двойное значение на основе некоторой логики и возвращаемых значений функции EvaluatePosition. По сути, функция Evaluate зависит от значений, возвращаемых функцией EvaluatePosition, но функцию необходимо тестировать изолированно, поэтому мне пришлось создать заглушку для функции EvaluatePosition и имитировать возвращаемые значения, устанавливая их изначально. Мой подход кажется пригодным для использования, единственное, что нужно, это следующее утверждение:

_gameBoardMock.CallBase = true;

Поскольку функция EvaluatePosition отклоняется, защищенные значения, которые она должна возвращать, не могут быть установлены Moq, поэтому я создал класс XGameBoard, который объявляет функцию EvaluatePosition_ShouldReturn, которая является общедоступной и может использоваться Moq, и таким образом я могу установить значения что нормальная функция EvaluatePosition должна вернуть:

_gameBoardMock.Setup (x => x.EvaluatePosition_ShouldReturn (i, j, PieceType.Cross)).Returns (1.0);

Поскольку функция EvaluatePosition переопределяется в классе XGameBoard, при вызове этой функции она вызывает функцию EvaluatePosition_ShouldReturn, значения которой установлены Moq, и должна возвращать указанные значения.

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

0 голосов
/ 12 апреля 2011

Трудно сказать, какое значение возвращается, поскольку вместо любого возврата у вас есть ....Из того, что я вижу, ваши циклы производственного кода начинаются с 0 и доходят до размера платы, тогда как ваша фиктивная установка нацелена на конкретные комбинации.

Если вы хотите, чтобы все комбинации были настроены, то просто не надоцикл в тесте и просто выполните:

_gameBoardMock.Setup (x => x.EvaluatePosition_ShouldReturn (
      It.IsAny<int>(), 
      It.IsAny<int>(), 
      It.IsAny<PieceType>())).Returns (1.0);

Но не видя, какая у вас логика в отношении того, как значение возвращается из метода Evaluate, тогда может быть какая-то другая причина.

Другой вариант - вообще не использовать MOQ.Поскольку у вас есть производный класс, вы можете просто изменить защищенный метод, чтобы он возвращал ваше значение.

protected override double EvaluatePosition (int row, int column, PieceType pieceType)
{
    return 1.0;
}
...