我经常设计系统,我的系统中有一个类,它有一堆受保护的方法。受保护的方法是因为它们应该可以被专业化访问,因此,我认为受保护的方法是我的通用类和任何专用类之间的契约。
因此,我想测试这些方法的行为是否正确,因此我的单元测试需要访问受保护的方法,这是c#中无法实现的,除非使用像反射这样的脏黑客。
我通常选择的解决方案是在单元测试中创建一个专门的类,将这些受保护的方法公开为public。因为我始终将单元测试保存在单独的程序集中,所以系统代码本身无法访问这些类,并且在我的系统代码中,受保护的函数仍然受到保护。
// In the system code assembly
namespace MySystem {
public class SomeClass {
protected void DoSomething() {
...
}
}
}
// In the unit test assembly
namespace MySystem.Unittests {
public class SomeClass2 : SomeClass {
public new void DoSomething() {
base.DoSomething();
}
}
}
我的单元测试现在能够通过实例化专门的类来测试父类的受保护成员的行为。
我还使用它来进一步模拟对象和模拟函数调用受保护的虚函数,但是这个代码有点复杂,所以我只是把它剪掉了。
我发现这种完成此任务的方式非常直接,以至于我不可能成为唯一这样做的人,因此我认为必须有一个共同的命名约定?
答案 0 :(得分:2)
我不确定我是否会在测试受保护的方法时看到这一点,但是,我从TDD的角度来讲。通常,您的测试是针对类的公共方法编写的。当您重构代码以提取内部使用的常用方法时,会出现受保护的方法。由于这些来自重构,您现有的测试已经涵盖了重构的代码。稍后通过公共专业化方法使用重构方法的代码的测试也会测试代码 - 在这种情况下,使用常见的受保护方法时,专业化的公共方法可以正常工作。
在对受保护方法的显式测试有意义的少数情况下,我没有看到使用反射来进行测试的危害。毕竟,你只是为了测试的目的打破了封装。
答案 1 :(得分:1)
不知道你正在做什么的模式名称,但.net有一个解决方案...使方法受保护内部,然后将以下内容添加到项目assemblyInfo文件
[assembly: InternalsVisibleToAttribute("[FQN of TestAssembly]")]
这将使项目中的内部方法对属性
中指定的测试程序集可见答案 2 :(得分:1)
当我不控制需要测试的类时,我才这样做了。 Charles指出在控制源代码时可以用.NET做什么。
您的情况有点不同,因为您的类旨在用作超类,因此通过子类进行测试非常有意义(因为该类不打算单独使用)。在这种情况下,您基本上是在做Test-Specific Subclass的变体。链接中描述的模式更多地是关于覆盖行为,如果你有一个没有先编写测试并具有高耦合的类,它是非常有用的,它是一种分离依赖关系的好方法(通常作为一个中间步骤,获取作为参数传递的单独类)。在您的情况下,“覆盖”是为了增加访问权限,但似乎符合相同的模式。