【问题标题】:How to set up mocked values for protected methods with moq?如何使用 moq 为受保护的方法设置模拟值?
【发布时间】:2011-04-11 13:57:36
【问题描述】:

以下面的类为例:

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

问题是 Evaluate 函数中的 EvaluatePosition 总是返回 0,而不是调用应该返回设置值的覆盖函数。

提前致谢。

【问题讨论】:

    标签: unit-testing moq


    【解决方案1】:

    很难说返回的是什么值,因为你有 ... 代替任何返回。据我所知,虽然您的生产代码循环从 0 开始,一直到电路板的大小,而您的模拟设置针对特定组合。

    如果您希望设置所有组合,那么不要进入测试中的循环,只需执行以下操作:

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

    但是如果没有看到您对如何从 Evaluate 方法返回值有什么逻辑,那么可能还有其他原因。

    另一种选择是根本不使用最小起订量。由于您有一个派生类,您可以简单地更改受保护的方法以返回您的值。

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

    【讨论】:

      【解决方案2】:

      我想进一步澄清一下这个问题。情况是 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 设置并且应该返回指定的值。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-25
        • 1970-01-01
        • 2016-03-09
        • 2016-05-29
        • 1970-01-01
        • 2012-01-08
        • 1970-01-01
        相关资源
        最近更新 更多