Lan*_*uhn 61 unit-testing mocking
我开始相信单元测试高级,编写良好的代码,需要大量使用模拟对象,几乎没有任何价值.我想知道这个断言是否正确,或者我错过了什么?
高级别是什么意思?这些是靠近食物链顶端的类和功能.它们的输入和输出往往是用户输入和用户界面.他们的大部分工作包括获取用户输入并对较低级别的实体进行一系列调用.它们通常很少或没有有意义的返回值.
写得好,我的意思是什么?在这种情况下,我指的是与其依赖关系(使用接口和依赖注入)分离的代码,并且逐行处于一致的抽象级别.没有棘手的算法,也没有条件限制.
我讨厌为这种代码编写单元测试.单元测试几乎完全由模拟对象设置组成.逐行,单元测试读取几乎像执行镜像.实际上,我通过查看实现来编写单元测试."首先我断言这个模拟方法被调用,然后我断言这个模拟方法被调用......"等我应该测试方法的行为,而不是它调用正确的方法序列.另一件事:我发现这些测试对于重构来说非常脆弱.如果测试非常脆弱,那么当被测代码被重构时,它会完全破碎并且必须重写,那么单元测试的主要好处之一是否已经丢失了?
我不希望这篇文章被标记为议论性的,或者不是问题.所以我将直接陈述我的问题:对我所描述的代码进行单元测试的正确方法是什么,或者是否理解并非一切都需要单元测试?
Rob*_*vey 44
根据我的经验,代码的较低级别(不是微不足道),单元测试的价值相对于编写它们所需的工作量而言.随着食物链越来越高,测试变得越来越精细,越来越昂贵.
单元测试至关重要,因为它们会告诉您何时在重构期间破坏某些内容.
更高级别的测试有自己的价值,但是它们不再被称为单元测试; 它们被称为集成测试和验收测试.需要进行集成测试,因为它们会告诉您不同软件组件的协同工作情况.
验收测试是客户签署的.验收测试通常由其他人(不是程序员)编写,以提供不同的视角; 程序员倾向于为可行的东西编写测试,测试人员试图通过测试不起作用的东西来打破它.
模拟仅适用于单元测试.对于集成和验收测试,模拟是无用的,因为它不运行实际的系统组件,例如数据库和通信基础结构.
wom*_*omp 20
只是触及你的粗体声明:
"我应该测试方法的行为,而不是它正在调用正确的方法序列"
被测对象的行为是它所采取的一系列动作.这实际上是"行为"测试,而当你说"方法的行为"时,我认为你的意思是有状态测试,就像在中,给它一个输入并验证正确的输出.
我之所以这样区别,是因为一些BDD纯粹主义者甚至认为测试你的课程应该调用什么更有意义,而不是输入和输出是什么,因为如果你完全知道你的系统是如何表现的,那么你的输入和输出将是正确的.
除此之外,我个人从不为UI层编写全面的测试.如果您正在为您的应用程序使用MVVM,MVP或MVC模式,那么在"1开发人员团队"级别,这对我来说是麻木不仁并且适得其反.我可以看到 UI中的错误,是的,在这个级别的模拟行为往往是脆弱的.我更关心的是确保我的底层域和DAL层正常运行.
什么是价值在顶层是一个集成测试.有一个网络应用程序?而不是断言您的控制器方法返回ActionResult(小值测试),编写一个集成测试,请求应用程序中的所有页面,并确保没有404或403.在每次部署时运行一次.
我总是遵循80/20规则进行单元测试.要想达到你所谈论的最高20%的覆盖率,那将是你努力的80%.对于我的个人和我的大部分工作项目,这都没有得到回报.
简而言之,我同意.我会编写集成测试,并忽略您描述的代码的单元测试.