这是一篇简单的文章,讨论了单元测试中遇到protected成员的应对方案。此外,在文章最后也希望和大家讨论一下某个特殊的情况下的处理方法。

protected是一个有趣而有用的修饰符,它把方法的访问成员严格限制在自身或自己的子类身上。换句话说,在使用过程中,protected成员对外部是开放的(因为其他类可以通过继承来使用该成员),又是封闭的(不是自身或子类的一切成员都无法访问)。而对于单元测试来说,protected成员又是尴尬的,因为它的“开放”意味着我们必须对它进行单元测试,而“封闭”又阻碍了我们在单元测试中涉及protected成员。

测试protected方法

现在有一个类,其中包含一个protected方法:

public class SomeClass
{protected int SomeMethod(string arg) { ... }
}

如果我们需要对这个protected方法进行单元测试,可以在测试代码中准备一个辅助类型:

public class SomeClassForTest : SomeClass
{public int PublicSomeMethod(string arg){return this.SomeMethod(arg);}
}

于是在单元测试中,便可以通过调用PublicSomeMethod来测试基类的SomeMethod方法:

var testClass = new SomeClassForTest();
var result = testClass.PublicSomeMethod(null);
Assert.Equal(0, result);

非常简单。

如果您觉得麻烦,也可以将SomeClass类中的SomeMethod方法改为protected internal,这样便可以在InternalVisibleTo的测试程序集中使用了。不过,我觉得为单元测试而改变成员的访问级别不是一个合适的做法。

对protected方法进行Mock

现在有一个类,其中有一个protected方法:

public class SomeClass
{protected virtual int SomeMethod(string arg) { ... }
}

并且,某个被测试的方法接受SomeClass作为参数。虽然被测试的方法不会直接调用SomeMethod方法,但是SomeMethod的实现会影响到公开接口的表现形式。于是,我们需要对SomeMethod进行Mock或Stub。为此,我们同样需要准备一个辅助类型:

public class MockSomeClass : SomeClass
{protected override int SomeMethod(string arg){return this.PublicSomeMethod(arg);}public virtual int PublicSomeMethod(string arg){return base.SomeMethod(arg);}
}

在MockSomeClass中,我们覆盖了基类的SomeMethod实现,使它调用了子类中公开的PublicSomeMethod方法,而PublicSomeMethod内部又调用了基类的SomeMethod方法。因此,如果您不去进行任何处理,那么MockSomeClass会保持SomeMethod的实现不变。而如果您需要对SomeMethod进行Mock或Stub的时候,便可以从PublicSomeMethod下手:

Mock<MockSomeClass> mockSomeClass = new Mock<MockSomeClass>() { CallBase = true };
mockSomeClass.Setup(c => c.PublicSomeMethod("123")).Returns(123);DoSomeTest(mockSomeClass.Object); // use the mock object

也很容易。

为了可测试性

值得注意的是,为了“可测试性”,第二部分中的protected方法必须是virtual的,因为我们需要在子类中进行override。同理,Mock框架能够辅助的方法也必须是virtual的,即使是一个public方法。那么,您觉得这是为了可测试性而做出的让步吗?或者换句话说,您觉得,一个不可以override的protected方法,但是会影响到其他公开接口的功能,这是不是一个合理的设计呢?如果这是一个合理的设计,又不想作出这样的让步……我们又该怎么做呢?

关于这点,我有自己的想法,不过还是想先听一下您的意见。

与protected成员有关的单元测试方式相关推荐

  1. php成员属性的声明方式,PHP中如何定义类及其成员属性与操作_PHP教程

    类的概念:类是具有相同属性和操作的一组对象的集合.它为属于该类的所有对象提供了统一的抽象描述,其内部包括属性和操作两个主要部分.在面向对象的编程语言中,类是一个独立的程序单位,它应该有一个类名并包括属 ...

  2. C++之继承探究(二):protected成员

    前文:C++之继承探究(一):继承的概念 protected成员   在下面右例中,子类虽然继承了父类的私有成员b_number,但是在子类的print()函数中依然不能直接访问该私有成员,子类只能通 ...

  3. C++使用命名空间中成员的三种方式

    通过简单的代码来介绍使用命名空间中成员的三种方式(我们最常用到的命名空间是是标准库std,下面的命名空间都以std为例): 使用作用域符:: 1 #include<iostream> 2 ...

  4. 私有private成员和保护protected成员的区别

    保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的. private 成员只能被本类成员(类内)和友元访问,不能被派生类访问: protected 成员可以被派 ...

  5. 私有继承与保护继承(protected 成员)

    私有继承(private): 继承的访问控制: 基类的public和protected成员:都以private身份出现在派生类中 基类的private成员:不可直接访问 访问权限: 派生类中的成员函数 ...

  6. 为什么 Java 与 Python 在对待成员变量的访问控制方式截然相反?

    转自知乎:http://www.zhihu.com/question/20885435 为什么 Java 与 Python 在对待成员变量的访问控制方式截然相反? Java提倡成员变量应该是priva ...

  7. C++ 笔记(16)— 类和对象(类定义、类实例对象定义、访问类成员、类成员函数、类 public/private/protected 成员、类对象引用和指针)

    1. 类的定义 类定义是以关键字 class 开头,后跟类的名称.并在它后面依次包含类名,一组放在 {} 内的成员属性和成员函数,以及结尾的分号. 类声明将类本身及其属性告诉编译器.类声明本身并不能改 ...

  8. 类的概念、成员函数的定义方式、类的访问控制和封装、类的大小、this指针

    文章目录 类的概念 struct class class和struct的区别是什么呢? 类中成员函数的两种定义方式 声明和定义都在类中 声明和定义分离 类的访问控制和封装 类的封装特性 类的大小 结构 ...

  9. Cpp 对象模型探索 / 类普通成员函数的调用方式

    C++设计时有一个要求,类普通成员函数的调用性能要和全局函数差不多.所以编译器在处理类的普通成员函数的宗旨是将其当作全局函数来处理. 为了达到上述目的,编译器会对类的普通成员函数进行如下操作: 在函数 ...

最新文章

  1. 最新!TUI世界大学排名(2021)发布:清华位居全球前20名!
  2. Pyhon 图片透明化
  3. 机器学习:使用numpy实现数据增强(Data Augmentation)
  4. 库存管理系统软件测试,药房库存管理系统模块测试用例
  5. Oracle Study--Oracle RAC CacheFusion(MindMap)
  6. leetcode367. 有效的完全平方数
  7. World Wind Java开发之八——加载本地缓存文件构建大范围三维场景(
  8. C语言的关键字 详解
  9. 【分享】这款微信电子名片真的很值得拥有!
  10. psp3000 java_psp上的python
  11. 树莓派 树莓派 编c++_如何建立一个树莓派冰箱的冷冻监视器
  12. ASP.NET 学习路线图
  13. 组策略设置桌面显示计算机图标,计算机组策略应用设置大全
  14. class path resource [applicationContext.xml] cannot be opened because it does not exist,jar包缺失
  15. 【Unity】Jay 开发日志(四)——道具效果的实现(下)
  16. 2244小游戏HTML5小游戏,2244小游戏:王者荣耀干扰正常游戏扣多少分 举报不成功是什么意思...
  17. 北宋三司若干问题研究
  18. python金融数据分析单元测试答案_参考答案2020智慧树知到Python金融数据分析
  19. 一文读懂shell命令
  20. 逃离塔克夫TT辅助注入器再次更新0.56

热门文章

  1. jsonp原生js跨域拿新浪数据插件封装【可扩展】
  2. 讨厌麻烦的ora 01722无效数字
  3. Windows 10 常用的快捷键及常用指令
  4. KMP算法详解 网络上转的。。。仰慕此人
  5. Swift傻傻分不清楚系列(二)数据类型
  6. 记录一次内网渗透试验
  7. 调用图片按钮的img图片
  8. iOS微博项目(七)发微博和定位
  9. Windows—JDK安装与环境变量配置
  10. lintcode:递归打印数字