RailsCasts中文版,#11 Refactoring User Name Part 2 重构实战2
2012-11-25 21:05
597 查看
在上一篇《RailsCasts中文版,#10 Refactoring User Name Part 1 重构实战1》我们讨论了重构,并演示了一个通过将代码移动到模型中以达到去除冗余的重构实例。不过这段代码依然还有优化的余地。
引入测试
在着手进一步重构
Rails缺省生成的测试类。
由于是自动生成的,代码逻辑知识简单的用
用于检测不含中间名用户的测试用例。
可以使用命令行
AutoTest的输出
好消息!测试通过了。我们再往
当代码保存后,AutoTest会自动执行用例。现在这两个用例都应该是执行成功的。
重构开始
在保证
对
保存代码后,自动测试的结果显示两个用例全都执行失败了。
AutoTest输出显示两个用例执行失败。
第一个用例失败的原因是,输出的中间名后面没有带上点号。第二个失败的原因是,当没有中间名时,名和姓之间放入了两个空格。先来改正第二个错误,这个错误产生的原因是无论是否有中间名,都会将各个名字用空格相连。修改这个问题,是在调用
重新执行用例后,只剩第一个问题了。我们重建一个叫
修改之后,两个用例都能跑过。但仍然有一种情况漏测了。那就是如果输入的中间名是一个空字符串的时候。写一个用例覆盖一下这种场景。
也能通过,结果正确。原因是
这样一来
重构后的状态
重构后的
与
注
视频是基于Rails 1录制的。代码使用Rails 2.2编写。
http://rubyforge.org/projects/zentest/
作者授权:Your welcome to post the translated text on your blog as well if the episode is free(not Pro). I just ask that you post a link back to the original episode on railscasts.com.
原文链接:http://railscasts.com/episodes/11-refactoring-user-name-part-2
class User < ActiveRecord::Base def full_name name = first_name + ' ' name += "#{middle_initial}. " unless middle_initial.nil? name += last_name end end
User类在上一节结束时的状态。
引入测试
在着手进一步重构
User之前,有必要了解一下测试。为了保证重构过程不对代码功能产生破坏,重构往往需要伴随着测试的介入。好的测试用例为重构质量保驾护航。通过
rails generate生成模型类的同时,也会生成对应的测试类。与
User类对应的是位于
/test/unit目录[1]的
user_test.rb文件。
require 'test_helper' class UserTest < ActiveSupport::TestCase # Replace this with your real tests. test "the truth" do assert true end end
Rails缺省生成的测试类。
由于是自动生成的,代码逻辑知识简单的用
true == true做了空实现。要用我们自己编写的测试逻辑代替。创建一个测试用例:新建没有中间名的用户,检查程序的输出是否和我们期待的一样。
test "full name without middle initial" do user = User.new(:first_name => "John", :last_name => "Smith") assert_equal 'John Smith', user.full_name end
用于检测不含中间名用户的测试用例。
可以使用命令行
rake test运行用例,但在这里我们准备使用自动测试工具AutoTest[2]。安装ZenTest gem(命令是
sudo gem install ZenTest)。使用自动测试的好处是他会适时的执行测试,以便当程序工作不正常时立刻就能被我们发现。运行autotest查看返回结果
Laa-Laa:ep11 eifion$ autotest loading autotest/rails /usr/local/bin/ruby -I.:lib:test -rtest/unit -e "%w[test/functional/users_controller_test.rb test/unit/user_test.rb].each { |f| require f }" | unit_diff -u Loaded suite -e Started . Finished in 0.046945 seconds. 1 tests, 1 assertions, 0 failures, 0 errors
AutoTest的输出
好消息!测试通过了。我们再往
UsetTest类中添加一个用来检测包含中间名这种情况的用例。
test "full name with middle initial" do user = User.new(:first_name => "Paul", :middle_initial => "P", :last_name => "Hughes") assert_equal 'Paul P. Hughes', user.full_name end
当代码保存后,AutoTest会自动执行用例。现在这两个用例都应该是执行成功的。
重构开始
在保证
full_name方法工作正常的基础上,我们准备开始重构了。局部变量
name其实可以去掉;字符串连接也可以被别的方法代替。取而代之的是将名字的每一部分分别放到数组中,调用数组的
join方法将他们用空格连接。
class User < ActiveRecord::Base def full_name [first_name, middle_initial, last_name].join(' ') end end
对
User类的第一次重构。
保存代码后,自动测试的结果显示两个用例全都执行失败了。
1) Failure: test_full_name_with_middle_initial(UserTest) [./test/unit/user_test.rb:11:in `test_full_name_with_middle_initial' /usr/local/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/testing/setup_and_teardown.rb:60:in `run']: --- /var/folders/yD/yDkhXjIsHAqkCTKsBbUlC++++TI/-Tmp-/expect31666.0 2009-01-04 11:23:35.000000000 +0000 +++ /var/folders/yD/yDkhXjIsHAqkCTKsBbUlC++++TI/-Tmp-/butwas31666.0 2009-01-04 11:23:35.000000000 +0000 @@ -1 +1 @@ -Paul P. Hughes +Paul P Hughes 2) Failure: test_full_name_without_middle_initial(UserTest) [./test/unit/user_test.rb:6:in `test_full_name_without_middle_initial' /usr/local/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/testing/setup_and_teardown.rb:60:in `run']: --- /var/folders/yD/yDkhXjIsHAqkCTKsBbUlC++++TI/-Tmp-/expect31666.1 2009-01-04 11:23:35.000000000 +0000 +++ /var/folders/yD/yDkhXjIsHAqkCTKsBbUlC++++TI/-Tmp-/butwas31666.1 2009-01-04 11:23:35.000000000 +0000 @@ -1 +1 @@ -John Smith +John Smith 2 tests, 2 assertions, 2 failures, 0 errors
AutoTest输出显示两个用例执行失败。
第一个用例失败的原因是,输出的中间名后面没有带上点号。第二个失败的原因是,当没有中间名时,名和姓之间放入了两个空格。先来改正第二个错误,这个错误产生的原因是无论是否有中间名,都会将各个名字用空格相连。修改这个问题,是在调用
join方法之前调用
compact方法。(
compact方法会从列表中移除掉所有的
nil值。)
def full_name [first_name, middle_initial, last_name].compact.join(' ') end
重新执行用例后,只剩第一个问题了。我们重建一个叫
middle_initial_with_full_stop的方法,根据是否有中间名,返回适当的字符串。
def full_name [first_name, middle_initial_with_full_stop, last_name].compact.join(' ') end def middle_initial_with_full_stop "#{middle_initial}." unless middle_initial.blank? end
修改之后,两个用例都能跑过。但仍然有一种情况漏测了。那就是如果输入的中间名是一个空字符串的时候。写一个用例覆盖一下这种场景。
test "full name with empty middle initial" do user = User.new(:first_name => "John", :middle_initial => "", :last_name => "Jones") assert_equal 'John Jones', user.full_name end
也能通过,结果正确。原因是
blank?方法对于空字符串和
nil都会返回
true,所以可以在调用
compact方法时被移除。
这样一来
User类的代码比以前更可读了。不过现在测试用例的代码有点重复了,关于测试用例的优化,下回分解。
重构后的状态
class User < ActiveRecord::Base
def full_name [first_name, middle_initial_with_full_stop, last_name].compact.join(' ') end def middle_initial_with_full_stop "#{middle_initial}." unless middle_initial.blank? end
end
重构后的
User类代码。
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "full name without middle initial" do user = User.new(:first_name => "John", :last_name => "Smith") assert_equal 'John Smith', user.full_name end
test "full name with middle initial" do user = User.new(:first_name => "Paul", :middle_initial => "P", :last_name => "Hughes") assert_equal 'Paul P. Hughes', user.full_name end
test "full name with empty middle initial" do user = User.new(:first_name => "John", :middle_initial => "", :last_name => "Jones") assert_equal 'John Jones', user.full_name end
end
与
User类对应的测试用例代码。
注
视频是基于Rails 1录制的。代码使用Rails 2.2编写。
http://rubyforge.org/projects/zentest/
作者授权:Your welcome to post the translated text on your blog as well if the episode is free(not Pro). I just ask that you post a link back to the original episode on railscasts.com.
原文链接:http://railscasts.com/episodes/11-refactoring-user-name-part-2
相关文章推荐
- RailsCasts中文版,#11 Refactoring User Name Part 2 重构实战2
- RailsCasts中文版,#12 Refactoring User Name Part 3 重构实战3
- RailsCasts中文版,#12 Refactoring User Name Part 3 重构实战3
- RailsCasts中文版,#10 Refactoring User Name Part 1 重构实战1
- RailsCasts中文版,#10 Refactoring User Name Part 1 重构实战1
- RailsCasts10 Refactoring User Name Part 1 重构User Name(一)
- Validating Common Form Input - Part 2 Validating a username
- 【slighttpd】基于lighttpd架构的Server项目实战(11)—C++的Name Mangling
- Spring Security 入门(3-11)Spring Security 的登录密码验证过程 UsernamePasswordAuthenticationFilter
- How to customise the TWebBrowser user interface (part 6 of 6)
- 走出重构(Refactoring)的误区
- ArcGIS水文分析实战教程(11)河流提取流程
- 【转】从判断Session["UserName"].ToString()为null和""所想到的
- change svn username
- Adapter模式实战之重构鸿洋集团的Android圆形菜单建行
- ognl.OgnlException: target is null for setProperty(null, "username")
- UsernamePasswordAuthenticationFilter
- 读重构 (Refactoring:Improving the Design of Existing Code)
- OAF学习笔记-11-页面传值(传ID,显示为Name)
- Oracle 数据库基础 出现invalid username/password; logon denied错误解决方案