c# - 在 C# 中使用 Mocks 和子类对受保护的方法进行单元测试
问题描述
我正在尝试对公共类中的一些受保护方法进行单元测试。我从这个类继承并通过从它返回超类的方法来测试继承的类。我的示例代码如下:
基类:
public class A
{
// Private variables here
public A(){ }
protected virtual bool MethodOfA()
{
bool returnValue = false;
//some operation here to set returnValue
return returnValue;
}
protected bool AnotherMethodOfA()
{
bool anotherReturnValue = false;
bool operationCheck = MethodOfA();
if(operationCheck)
{
//do something to set the value of anotherReturnValue
}
return anotherReturnValue;
}
}
继承类:
public class B : A
{
// Private variables here
public B():base() { }
public new bool MethodOfA()
{
return base.MethodOfA();
}
public new bool AnotherMethodOfA()
{
var testMock = new Mock<A>();
//This is the part where I'm not sure how to get it to work.
testMock.CallBase = true; // I have tried it with and without this statement. couldn't get it to work
testMock.Protected()
.Setup<bool>("MethodOfA")
.Returns(true);
return base.AnotherMethodOfA();
}
}
测试:
public class TestB
{
private readonly B _sut
//some Mocks here for setup
public TestB()
{
_sut = new B();
}
[Fact]
public void AnotherMethodOfA_Test()
{
var result = _sut.AnotherMethodOfA();
Assert.True(result);
}
}
我需要的基本上是,当我从 TestB 类运行我的测试时,它在需要调用 'MethodOfA()' 的那个方法中点击 '_sut.AnotherMethodOfA()',它应该只使用我提供的值在 Mock 中继续执行,而不是调用实际的方法(它现在正在执行)。
现在,如果我的 Method-Under-Test 更简单并且不在其中调用另一个方法,那么整个事情就会很简单(在我的许多其他方法中就是这种情况,我已经成功地测试了这些方法),但是由于这种方法在执行过程中调用另一个方法,我需要模拟这个中间方法并将其传递给我的被测方法。
解决方案
这很好,因为你可以用一块石头杀死两只鸟:减少或消除继承,以及使用依赖注入。
与其创建protected
方法,不如将方法所做的事情想象为您的类所依赖的抽象。
代替
protected bool AnotherMethodOfA()
想象
public interface IThingThatDoesSomethingAndReturnsABoolean
{
bool MethodThatReturnsBool();
}
或者
public delegate bool FunctionThatReturnsBool();
然后,重写类A
如下:
public class A
{
private readonly IThingThatDoesSomethingAndReturnsABoolean _thing;
public A(IThingThatDoesSomethingAndReturnsABoolean thing)
{
_thing = thing;
}
protected bool AnotherMethodOfA()
{
bool anotherReturnValue = false;
bool operationCheck = _thing.MethodThatReturnsBool();
if (operationCheck)
{
//do something to set the value of anotherReturnValue
}
return anotherReturnValue;
}
}
如果您需要更改返回 a 的任何内容的实现,则bool
不必通过继承来完成A
。这是一种常见的模式,但它往往会纠缠不清并产生问题,包括您要询问的确切问题。
相反,您所要做的就是提供不同的IThingThatDoesSomethingAndReturnsABoolean
.
现在一切都可以测试了。您可以A
通过提供接口的模拟来进行测试。您希望返回 的方法bool
是可测试的,现在是因为它不再是protected
某个其他类的方法。
这被称为优先组合而不是继承。不是让类通过相互继承来协同工作,而是编写单独的类来完成不同的事情并将它们组合在一起以协同工作。
A
如果您的依赖类需要它以前作为属性或字段访问的值“拥有” ,您可以将它们作为方法的参数。这使得很容易准确地查看该方法需要多少信息A
。
在某些情况下继承是有意义的,但是将功能分离为依赖项而不是将它们构建到继承层次结构中是一种很好的做法,这将使您的代码可测试并防止以后可能出现的其他问题。
推荐阅读
- python - 如何在Django中查询集的每个对象上执行一个方法并返回一个列表?
- javascript - 返回 JSON 字符串的 JavaScript 函数
- python - df.to_csv 写入的文件不能被 pd.read_csv 读取
- regex - IIS URL Rewrite Match # in part of URL
- javascript - 使 Django Data-Url 属性字符串形式在 .prepend 中工作
- angular - 如何设置输入角度的默认值?
- android - 如何修复 Retrofit Android Studio 中的 500 响应代码错误
- firebase - 如何在 Firebase 模拟器中存根外部服务?
- javascript - 在 Firestore 中添加新字段
- java - Java 11 的 Evosuite 插件问题