首页 > 解决方案 > 如何获取在模拟类中调用的方法的结果

问题描述

有一种方法可以获取从调用到模拟对象的方法返回的结果?

例如,如果我有以下类和接口:

DoSomethingClass.cs

public class DoSomethingClass
{
  
  IInternalClass _intClass;

  public DoSomethingClass(IInternalClass intClass)
  {
    _intClass = intClass;
  }
  
  void DoSomething(int number)
  {
    // do some transformation to the number, e.g.
    var transformedNumber = number * (number - 1);
    
    var x = _intClass.IsEven(transformedNumber);

    // do something else
  }
}

内部类.cs

public interface IInternalClass
{
  bool IsEven(int number);
}

public class InternalClass: IInternalClass
{
  
  public InternalClass();
  
  public bool IsEven(int number)
  {
    return number % 2 == 0;
  }
}

和一个测试类:

测试.cs

public class Tests
{
  [Fact]
    public async Task test_something()
    {

        //PREPARE
        var request = 10

        var internalMock = new Mock<IInternalClass>();
        var classToTest = new DoSomethingClass(internalMock.Object);

        // ACT

        await classToTest.DoSomething(request);

        //ASSERT

        //Here I want to check if the method IsEven of the internal class return the right result
    }
  }
}

我要断言的是main方法里面被调用的方法IsEven的返回值,我没有办法知道这个方法里面的计算并传递给。InternalClassDoSomethingtransformedNumberIsEven

注意:我使用Moq库来模拟对象。

请原谅我上面那个愚蠢的例子,但是我没有任何简单的真实代码可以在这里展示,但是我希望这足以理解这个问题。

标签: c#mockingmoq

解决方案


我假设您想验证您的 IsEven 方法是否在模拟的 IInternalClass 上被调用?

如果是这种情况,那么您可以在模拟上使用验证方法,如下所示:

[Fact]
public void DoSomething_Verify()
{
    var request = 10;
    var internalMock = new Mock<IInternalClass>();
    var classToTest = new DoSomethingClass(internalMock.Object);

    classToTest.DoSomething(request);

    //Verify that the mock is invoked with the expected value, the expected number of times
    internalMock.Verify(v => v.IsEven(90), Times.Once);
    //There are lots of other options for Times, e.g. it is never called with an unexpected value maybe.
    internalMock.Verify(v => v.IsEven(91), Times.Never);
}

此外,要使用 await 调用 DoSomething 方法,您需要更改方法签名,如下所示:

public async Task DoSomethingAsync(int number)
{
    // do some transformation to the number, e.g.
    var transformedNumber = number * (number - 1);

    var x = _intClass.IsEven(transformedNumber);

    // do something else
}

然后你可以像这样创建一个单元测试:

[Fact]
public async void DoSomething_VerifyAsync()
{
    var request = 10;
    var internalMock = new Mock<IInternalClass>();
    var classToTest = new DoSomethingClass(internalMock.Object);

    //To call the DoSomething method with await the method needs the async Task and a good convention is to append Async to the name
    await classToTest.DoSomethingAsync(request);

    //Another slightly more generic option is to verify that the mock was called with and int exactly n Times
    internalMock.Verify(v => v.IsEven(It.IsAny<int>()), Times.Exactly(1));
}

推荐阅读