如何使用 NSubstitute 模拟受保护的方法

Kar*_*n M 10 c# unit-testing mocking object nsubstitute

public static void Mock(out IProgram prog, out IJson json)
{    
    prog = Substitute.For<IProgram>();
    IJson = Substitute.For<IJson>();

    prog.SaveProg(1, 1, 1, "Somthing", 1, DateTime.UtcNow,
                 (DateTime.UtcNow + TimeSpan.FromDays(10)), 
                 10, "someemail@email.com", DateTime.UtcNow, 1)
        .Returns(ObjectResult<int?>); 
}
Run Code Online (Sandbox Code Playgroud)

我在调用时收到错误,Returns(ObjectResult<int?>)因为它ObjectResult是受保护的类。我如何解决这个问题以便能够从实际方法调用我的模拟方法?

meJ*_*rew 14

在调用替代方法后,NSubstitute 会覆盖该方法的行为,但它实际上并不关心您如何调用该方法。这允许您通过反射来调用它。

下面是一个非常详细的例子:

public class SomeRepository
{
    public string ReadData() => ActuallyPerformDataReading();
    protected virtual string ActuallyPerformDataReading() => "some wrong data";
}

public class SomeClass
{
    SomeRepository _someRepository;
    public SomeClass(SomeRepository someRepository)
    {
        _someRepository = someRepository;
    }

    public string ReadSomething() => _someRepository.ReadData();
}


var repositorySub = Substitute.For<SomeRepository>();
repositorySub.GetType().GetMethod("ActuallyPerformDataReading", BindingFlags.NonPublic | BindingFlags.Instance)
    .Invoke(repositorySub, new object[] {}).Returns("some test data");
var sut = new SomeClass(repositorySub);

var result = sut.ReadSomething(); //"some test data"
Run Code Online (Sandbox Code Playgroud)


Nec*_*ras -4

您不应该能够模拟受保护的类/方法。它受到明确的保护,因此您不能这样做。如果您需要嘲笑它,请将其公开。如果这是别人的方法并且您认为需要模拟它,那么您可能测试不正确。

编辑:受保护方法中的任何功能只能由同一类中的公共方法使用。模拟该公共方法以按照您想要的方式执行受保护方法的某些所需结果。

  • 我无法更改访问修饰符。除了我已经知道的以外,你还有什么建议吗? (3认同)
  • 方法不太可能被标记为受保护以明确防止模拟/防止创建测试替身。在某些情况下,例如“ObjectResult&lt;T&gt;”,专门添加受保护的构造函数以方便创建测试替身。https://msdn.microsoft.com/en-us/library/mt154818(v=vs.113).aspx#M:System.Data.Entity.Core.Objects.ObjectResult`1。 (2认同)