【问题标题】:Mock virtual methods and not mock overridden of this methods with Moq模拟虚拟方法,而不是使用 Moq 模拟此方法的覆盖
【发布时间】:2018-01-04 10:04:01
【问题描述】:

在下面的代码中,我想在 FooBase 类中模拟 GetTitle(int id) 的 DB 操作。但我想在覆盖的GetTitle(int id) 中测试验证部分。

我想测试被覆盖的方法,但要模拟基础方法

我如何模拟虚拟方法并测试它的覆盖?

public abstract class FooBase
{
    public virtual string GetTitle(int id) { return "Title From DB" /*Select From DB*/; }
}

public class Foo : FooBase
{
    public override string GetTitle(int id)
    {
        if (id < 0)
            return "Invalid id";

        /*Doing somethings like other validations and etc*/

        return $"Valid ID ({base.GetTitle(id)})";
    }
}

public class FooTests
{
    [Fact]
    public void GetTitle() // Fails
    {
        // Arrange
        var expectedID = 1;
        var expectedResult = "Test";
        var fooMock = new Mock<Foo>();
        fooMock.Setup(x => x.GetTitle(It.IsAny<int>())).Returns(expectedResult);
        var foo = fooMock.Object;

        // Act
        var title = foo.GetTitle(expectedID);

        // Assert
        fooMock.Verify(x => x.GetTitle(It.Is<int>(c => expectedID == c)), Times.Once);
        Assert.Equal($"Valid ID ({expectedResult})", title);
    }
}

【问题讨论】:

  • 这就是继承的工作原理。 Moq 动态创建Foo 的继承者(称为代理),因此它完全有自己的GetTitle 实现,您可以告诉它调用它自己的基础或通过Moq 为您提供的方式提供一些自定义行为,这是“返回一些值”或“抛出一些异常”。您不能从继承链上的任意类中模拟出基本实现。很抱歉,总体而言,您在设计方面走的是一条完全错误的道路。
  • @MarioDS 这里的正确设计是什么?

标签: unit-testing moq xunit


【解决方案1】:

如果您可以将您的逻辑分成不同的方法(这也可能是一个更好的设计),那么您可以使用 Moq 的 CallBase 属性来使测试调用模拟方法。

public abstract class FooBase
{
   public virtual string GetTitle(int id) { return "Title From DB" /*Select From DB*/; }
}

public class Foo : FooBase
{
  public virtual string GetValidatedTitle(int id)
  {
    if (id < 0)
    return "Invalid id";

    /*Doing somethings like other validations and etc*/

    return $"Valid ID ({GetTitle(id)})";
  }
}

public class FooTests
{
  [Fact]
  public void GetTitle() // Now Passes
  {
    // Arrange
    var expectedID = 1;
    var expectedResult = "Test";
    var fooMock = new Mock<Foo>() { CallBase = true };
    fooMock.Setup(x => x.GetTitle(It.IsAny<int>())).Returns(expectedResult);
    var foo = fooMock.Object;

    // Act
    var title = foo.GetValidatedTitle(expectedID);

    // Assert
    fooMock.Verify(x => x.GetTitle(It.Is<int>(c => expectedID == c)), Times.Once);
    Assert.Equal($"Valid ID ({expectedResult})", title);
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-31
    • 1970-01-01
    • 1970-01-01
    • 2012-11-28
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 2010-11-12
    相关资源
    最近更新 更多