如何使用moq为受保护方法设置模拟值?

时间:2011-04-11 13:57:37

标签: unit-testing moq

例如,参加以下课程:

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函数编写一个测试,但这又取决于被声明为protected的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);

问题是Evaluate函数中的EvaluatePosition总是返回0,而不是调用overriden函数,它应返回已设置的值。

提前致谢。

2 个答案:

答案 0 :(得分:0)

由于您...代替任何回报,很难说返回了什么值。从我所看到的,虽然你的生产代码循环从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;
}

答案 1 :(得分:0)

我想再澄清一下这个问题。情况是Evaluate函数应该根据一些逻辑和EvaluatePosition函数的返回值返回一个double值。基本上,Evaluate函数取决于EvaluatePosition函数返回的值,但该函数必须单独测试,因此我必须为EvaluatePosition函数创建一个存根,并通过最初设置它们来模拟返回值。我的方法似乎是可用的,唯一需要的是以下声明:

_gameBoardMock.CallBase = true;

因为EvaluatePosition函数被解析保护,它应该返回的值不能由Moq设置,因此我创建了XGameBoard类,它声明了由Moq公开和可用的EvaluatePosition_ShouldReturn函数,这样我可以设置值正常的EvaluatePosition函数应该返回:

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

因为在XGameBoard类中覆盖了EvaluatePosition函数,所以当调用此函数时,它将调用EvaluatePosition_ShouldReturn函数,该函数的值由Moq设置并应返回指定的值。

我希望有些人可能会发现这种方法对单元测试很有用。快乐的编码。