使用 Moq 在 C# 中进行单元测试受保护的方法
最近我注意到,您可以使用 Moq 对抽象基类进行单元测试,而不是在测试中创建实现抽象基类的虚拟类。请参阅如何使用最小起订量测试抽象类中的具体方法? 例如,您可以这样做:
public abstract class MyAbstractClass
{
public virtual void MyMethod()
{
// ...
}
}
[Test]
public void MyMethodTest()
{
// Arrange
Mock<MyAbstractClass> mock = new Mock<MyAbstractClass>() { CallBase = true };
// Act
mock.Object.MyMethod();
// Assert
// ...
}
现在我想知道是否有类似的技术可以让我测试受保护的成员,而无需创建包装类。即你如何测试这个方法:
public class MyClassWithProtectedMethod
{
protected void MyProtectedMethod()
{
}
}
我知道 Moq.Protected 命名空间,但是据我所知它只允许你设置期望,例如
mock.Protected().Setup("MyProtectedMethod").Verifiable();
我也知道这里明显的答案是“不要”测试受保护的方法,仅测试公共方法”,但是这是另一场争论!我只是想知道使用起订量是否可以实现这一点。
更新:下面是我通常测试的方法:
public class MyClassWithProtectedMethodTester : MyClassWithProtectedMethod
{
public void MyProtectedMethod()
{
base.MyProtectedMethod();
}
}
提前致谢。
It came to my attention lately that you can unit test abstract base classes using Moq rather than creating a dummy class in test that implements the abstract base class. See How to use moq to test a concrete method in an abstract class? E.g. you can do:
public abstract class MyAbstractClass
{
public virtual void MyMethod()
{
// ...
}
}
[Test]
public void MyMethodTest()
{
// Arrange
Mock<MyAbstractClass> mock = new Mock<MyAbstractClass>() { CallBase = true };
// Act
mock.Object.MyMethod();
// Assert
// ...
}
Now I was wondering if there was a similar technique to allow me to test protected members without having to create a wrapper class. I.e. how do you test this method:
public class MyClassWithProtectedMethod
{
protected void MyProtectedMethod()
{
}
}
I'm aware of the Moq.Protected namespace, however as far as I can see it only allows you to setup expectations with e.g.
mock.Protected().Setup("MyProtectedMethod").Verifiable();
I'm also aware that the obvious answer here is "don't test protected methods, only test public methods", however that's another debate! I just want to know if this is possible using Moq.
Update: below is how I would test this normally:
public class MyClassWithProtectedMethodTester : MyClassWithProtectedMethod
{
public void MyProtectedMethod()
{
base.MyProtectedMethod();
}
}
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Moq 中调用受保护成员的另一种方法是以下模板:
在您的类中,使用受保护成员将您的函数标记为虚拟。
例如:
然后在您的单元测试中添加对 的引用
,并且在您的单元测试中您可以编写以下内容:
记下 ItExpr。应该使用它来代替 It。可验证的另一个问题正在等待着您。我不知道为什么,但如果不调用可验证验证将不会被调用。
Another way in Moq to call protected member is the following template:
In your class, with protected member mark your function as virtual.
For example:
Then in your unit test add reference to
and in your unit test you can write the following:
Take note of ItExpr. It should be used instead of It. Another gotcha awaits you at Verifiable. I don't know why, but without calling to Verifiable Verify will not be called.
对于初学者来说,对抽象方法进行单元测试是没有意义的。没有实施!您可能想要对不纯的抽象类进行单元测试,验证是否调用了抽象方法:
请注意,我设置 CallBase 将其转换为部分模拟,以防 Do 是虚拟的。否则 Moq 将取代 Do 方法的实现。
使用 Protected() 您可以验证是否以类似的方式调用了受保护的方法。
当您使用 Moq 或其他库创建模拟时,重点是覆盖实现。测试受保护的方法涉及公开现有的实现。这不是 Moq 的设计目的。 Protected() 只是让您能够访问(可能是通过反射,因为它是基于字符串的)来覆盖受保护的成员。
要么编写一个带有调用受保护方法的方法的测试后代类,要么在单元测试中使用反射来调用受保护方法。
或者,更好的是,不要直接测试受保护的方法。
For starters, there's no point in unit testing an abstract method. There's no implementation! You may want to unit test an impure abstract class, verifying that the abstract method was called:
Note that I set CallBase to turn this into a partial mock, in case Do was virtual. Otherwise Moq would have replaced the implementation of the Do method.
Using Protected() you could verify that a protected method was called in a similar manner.
When you create a mock with Moq or another library, the whole point is overriding implementation. Testing a protected method involves exposing existing implementation. That's not what Moq is designed to do. Protected() just gives you access (presumably through reflection, since it's string-based) to override protected members.
Either write a test descendant class with a method that calls your protected method, or use reflection in the unit test to call the protected method.
Or, better yet, don't test protected methods directly.
您已经触及“测试公共 API,而不是私有 API”的思维过程,并且还提到了从类继承然后以这种方式测试其受保护成员的技术。这两种方法都是有效的。
在这一切之下,一个简单的事实是,您认为这个实现细节(因为这就是私有或受保护的成员)足够重要,可以直接测试,而不是通过使用它的公共 API 间接测试。如果它如此那么重要,也许它的重要性足以提升到它自己的类别。 (毕竟,如果它如此重要,也许这是
MyAbstractClass
不应该承担的责任。)类的实例将在MyAbstractClass
内部受到保护,因此只有基类派生类型可以访问实例,但类本身将是完全可测试的,并且如果需要的话可以在其他地方使用。否则,您将只能采用您已经确定的方法。
*起订量可能会也可能不会提供某种获取私有或受保护成员的机制,我不能说,因为我不使用该特定工具。我的回答更多是从架构的角度来看的。
You've already touched upon the "test the public API, not private" thought process, and you've also already mentioned the technique of inheriting from the class and then testing its protected members that way. Both of these are valid approaches.
Beneath it all, the simple truth is that you consider this implementation detail (as that's what a private or protected member is) important enough to test directly rather than indirectly via the public API that would use it. If it is this important, perhaps it's important enough to promote to its own class. (After all, if it's so important, perhaps it is a responsibility that
MyAbstractClass
should not have.) The instance of the class would be protected insideMyAbstractClass
, so only the base and derived types would have access to the instance, but the class itself would be fully testable otherwise and usable elsewhere if that became a need.Otherwise, you're left* to the approaches you've already identified.
*Moq may or may not provide some mechanism for getting at private or protected members, I cannot say, as I do not use that particular tool. My answer is more from an architectural standpoint.