Set expectations

你不可能把一个老旧的代码野兽只用一晚就转变成优雅的奇迹marvel.你需要如下做法:

  • 让自己有好的状态,用15分钟挥舞拳头诅咒之前的程序员
  • 开始工作,这个codebase现在归你了。
如果你像我一样,立即搞定每件事并或增加测试给每件事的冲动十分强烈,那么休闲让这个感觉过去。

一上来就给遗产代码增加测试不是好注意,这里有2个原因:

第一个问题是,你接管这个遗产代码后你期望做点什么,而客户的想法未必和你一样。所以先和客户交流,或者和产品经理充分交流,确定需求后再开始。

第二个问题是, 不得不处理 常常的矛盾的遗产代码。遗产代码常常太互相过度依赖或者不好理解,导致难以使用单元测试。除非你先进行重构。但是不经过单元测试就重构更容易导致bugs,特别是你还没有完全理解这些新代码。

这2个问题都导致快速的处理遗产代码是不可能的事情。

工作代码中那些不是十分明确需要改变的代码就别改。如果它运行的很好并且需求也和以前一样,唤醒沉睡的熊(比喻)只能让你远离你的最重要的事。

对于遗产代码,逐步前进,走你能确定的小步。保证自己写的新代码通过测试。当你写新代码时,对现存的代码做小的改进,让总体的代码基础变好。


Getting Started with Legacy Code

做3件事情:

get the code in source control

让代码处于版本控制Source Control。可能它已经处于版本控制,但你应该小心。确认你有所有的存取权利对任何你需要的代码仓库code repository。最好使用Git或者其他版本控制系统让你可以创建和管理branches。这样你可以轻松的通过使用分支来探索源代码的变化,根据需要让scratch pads缓存可以被保存或丢弃。

get the code running

产品环境的设置, 推迁移产品环境到一个更标准的地方。Docker是一个有用的container tools. 可以把产品环境复制到a Docker container.

get the Test Suite running

如果之前的团队不认真的写测试,你的工作就会变难。 你可能有各种测试不通过或者坏掉。

(前辈的一个简单原则:如果你不能在5分钟弄明白一个测试是做什么的,就删除它)

利用这个机会了解遗产代码是如何运行的,但此时还不能代码让它通过测试 。如果你不能弄明白如何让一个测试通过,注释它,甚至删除它;增加一个注释,当你更全面的了解了测试框架后再回来看它。当前全面的测试不是优先事项。 当前优先事项是为了的工作让基础的测试通过。

如果代码使用的是旧版本的RSpec,更新RSpec。


Test-Driven Exploration

black-box testing:

忽略内部结构,测试顶层的输入系统和返回的输出。集成测试,用户输入和系统输出。

因为集成测试是从外部工作的,可以用它来测试遗产代码。不用涉及全面的应用,而是涉及全部功能。

white-box testing:

使用关于系统内部的知识来精确地测试明确的路径。

角色测试:

首先,选择一个方法来测试。这个方法应该涉及一个你计划做的变化 。

然后,写这个测试,我们知道测试会失败。不用深挖内部。先期待一个不可能的结果。让测试告诉你真实结果是什么。

运行测试,测试报告error因为有缺少的依靠,或者测试报告fail因为代码运行了但spit out a different result。

分析:

大多时候会升起error, 因为这里肯定你不知道的一些对象依赖,一些value是不被期待的,或者你在其他方面打破了遗产代码函数的the delicate balance。

你需要弄明白事物。常常不得不创建更多的对象。

最终搞定errors后,你会进一步的理解程序的内部。

然后就可以进行下一个测试了,大多数是在其他测试案例中尝试现存的方法 .

Prescription
当开始给遗产代码写单元测试时,使用测试来探索代码的行为。尝试在不改变原code的情况下写一个passing test,用测试来反应问题。

Pry对此是有帮助的。一旦在console能明白事情,转化这个命令给测试以便它们能反复运行。


What Tool Should I Use? (Legacy Edition)

之前用什么工具,这里也用这个工具。如果没有使用factory,作者推荐用。设置一个factory工具来创建关联会节省时间。

⚠️提示 :

如果原来的程序员使用的工具不足以支持你想要的测试或者现存的测试你觉得是无用的,那么删除它们,从新开始。此时你可以挑选你想要的任何工具。


Dependency Removal  依赖移除

在遗产测试中,依赖是最大的挑战。可能TDD code最帮的优势就是测试会强迫代码的各个独立片段之间最大化的相互独立。

Keep Things Separate

让你的新代码不要依赖遗产代码最容易的办法是你自己分开它们。如果可能,在新的类或新的方法中写新代码。仅仅调用那些遗产代码。

如果你新增或者提取了大量函数,你需要考虑创建你自己的独立类而不是仅仅增加一个方法。

出于测试目的,移动新代码到一个新的类能让测试新的代码更容易,因为新代码较少依赖现存的程序。

不过这样做,也有短期的不好效果,让代码不好懂(因为逻辑增加了)。 在任何案例,你都在原始的混乱代码和更好的重构和组织版本之间的过渡状态。

Legacy Databases, Testing, and You

column contraint 列的约束。

你有可能遇到混乱的数据结构。如奇怪的命名约定或者不常见的ActiveRecord功能。但是它们不影响你测试功能的能力。

你需要小心的是十分数据库增加了非常不明显的约束代码。如foreign key约束。尤其是老版本rails。

从一个测试透明度来看,这个问题更严重。首先业务逻辑在rails代码之外,在数据库里。这样的逻辑很难发现和测试以及改变。更坏的是,foreignkey约束增加了某些对象件的依赖。在测试环境中,一些对象需要一起创建导致了奇怪的bugs。因此需要留意一个重数据库而不信任activerecord的开发团队的遗产代码。

Using Test Doubles to Remove Dependencies

使用double, mock, stub来启动测试,测试那些没有被测试过的代码。

在遗产代码中,这样的好处是使用test doubles可以从程序中隔离单独的class和方法,把关注点放在你所注意的部分。

比如当前测试会用到一个不是当前需要测试的相关方法,你只需要设定一个正确的返回值就行了。这样就把注意力集中在你需要注意的部分。

如,把credit_card_is_valid?设置成一个stub,方便之后的运行。

allow(order).to receive(:credit_card_is_valid?).at_least(:once).and_return(true)


Find the Seam

A seam是一个你可以改变程序的行为但无需改动代码的地方。通过在代码中找到seam并利用它们来测试遗产函数。

A test double可以称为a seam是因为在测试中增加的double,通过授权对一个方法调用产生一个指定的响应,改变了程序代码的行为,但实际上没有执行这个方法。同时,在测试环境中,这个方法的行为改变现存的开发代码也就不会影响到产品代码。


do one thing at a time, to the extent possible.

当你增加新的功能时,不要扩展测试范围。

当你扩展测试范围时,不要试图把代码弄的太整洁。(有时难以避免)

每一步,做的事情尽可能的少,这样一旦发现错误就容易定位到。

Rails 5 Test Prescriptions 最后一章,如何测试继承下来的代码,legacy code的更多相关文章

  1. Rails 5 Test Prescriptions 第4章 什么制造了伟大的测试

    伴随着程序成长,测试变长,复杂性增加,如何更高效的写测试,对以后开发不会造成麻烦. 测试本身没发被测试,所以一定要清楚,可控.不要加循环,不要过于复杂的自动编程. Cost and Value 成本和 ...

  2. Rails 5 Test Prescriptions 第11章其他部分的测试。

    Routes✅ Helper Methods✅ Controllers and Requests✅ Simulating Requests⚠️,看之前的博客 What to Expect in a R ...

  3. Rails 5 Test Prescriptions 第9章 Testing-JavaScript: Integration Testing,❌挂一个问题webpacker::helper

    使用Capybara进行JS的集成测试 谈论驱动 让测试通过 Webpack in Development Mode Js设计 是用户在网页上有好的体验的重要因素. 尽管如此,许多网页不测试JS. 部 ...

  4. Rails 5 Test Prescriptions 第8章 Integration Testing with Capybara and Cucumber

    Capybara:  A complete reference is available atrubydoc.info. 集成测试就是把局部的程序组合起来测试. 端到端测试是一个特殊的集成测试,覆盖了 ...

  5. Rails 5 Test Prescriptions 第5章 Testing Models

    Rails,model层包含业务逻辑和储存逻辑.其中储存逻辑被ActiveRecord处理. 在model中,不是每件事都必须是ActiveRecord对象.model layer可以包含各种服务,对 ...

  6. Rails 5 Test Prescriptions 第3章Test-Driven Rails

    本章,你将扩大你的模型测试,测试整个Rails栈的逻辑(从请求到回复,使用端到端测试). 使用Capybara来帮助写end-to-end 测试. 好的测试风格,包括端到端测试,大量目标明确的单元测试 ...

  7. Rails 5 Test Prescriptions 第10章 Testing for Security

    Web 安全是一个可怕的主题.所有的你的程序都依靠密码学,代码超出了你的控制. 尽管如此,你还是可以控制部分网页安全 --所有的logins和access checks和injection error ...

  8. Rails 5 Test Prescriptions 第10章 Unit_Testing JavaScript(新工具,learn曲线太陡峭,pass)

    对Js的单元测试是一个大的题目.作者认为Ruby的相关测试工具比Js的测试工具更灵活 大多数Js代码最终是关于响应用户的行为和改变DOM中的元素 没有什么javascript的知识点.前两节用了几个新 ...

  9. Rails 5 Test Prescriptions 第7章 double stub mock

    https://relishapp.com/rspec/rspec-mocks/v/3-7/docs/basics/test-doubles 你有一个问题,如果想为程序添加一个信用卡程序用于自己挣钱. ...

随机推荐

  1. 170622、springboot编程之JPA操作数据库

    JPA操作数据库 什么事JAP?JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中. 1.在pom ...

  2. 写出gradle风格的groovy代码

    写出gradle风格的groovy代码 我们先来看一段gradle中的代码: buildscript { repositories { jcenter() } dependencies { class ...

  3. Servlet------>request和response控制编码乱码问题

    我在request篇和response都有提到,觉得会忘记,所以从新整理一下 request细节四----->通过request控制编码问题 第一种方式是通过设置------>reques ...

  4. 锁、volatile、CAS 比较

    一.锁的劣势 (1) 在JDK1.5之前都是使用synchronized关键字保证同步的,这种通过使用一致的锁定协议来协调对共享状态的访问,可以确保无论哪个线程持有守 护变量的锁,都采用独占的方式来访 ...

  5. IP层网络安全协议(IPSec)技术原理图解——转载图片

  6. Mirror--自增键在镜像中的影响

    测试环境: OS: Windows Server 2008 R2 Enterprise SQL: SQL Server 2012 Enterprise 测试场景: 有SERVER A上数据库 DB10 ...

  7. centos7上安装php5.6

    配置yum源 追加CentOS 6.5的epel及remi源. # rpm -Uvh http://ftp.iij.ad.jp/pub/linux/fedora/epel/6/x86_64/epel- ...

  8. 转:CentOS设置程序开机自启动的方法

    转自:http://www.centos.bz/2011/09/centos-setup-process-startup-boot/ 1.把启动程序的命令添加到/etc/rc.d/rc.local文件 ...

  9. Qt多线程同步总结

    1.QMutex   QMutex mutex;   void func() { mutex.lock(); ........ mutex.unlock(); }   2.QMutex联手QMutex ...

  10. 实现Vue-MVVM-step1

    一个利用defineProperty实现的MVVM双向数据绑 <!DOCTYPE html> <html lang="en"> <head> & ...