BDD 作为一种设计方法,可以有效的改善设计,并在系统的演化过程中为团队指明前进方向。
RubyOnRails中具体使用的工具叫cucumber,这部分也可完全做客户需求的代替,是敏捷开发重要基石,不过本文不是主要讲这个,到现在还没接触到什么cucumber的资料
二. 什么又叫测试驱动开发,英文全称Test-Driven Development,(简称TDD)
测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统软件开发流程的新型的开发方法。它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。这有助于编写简洁可用和高质量的代码,并加速开发过程。
RubyOnRails中具体用到的工具叫Rspec,也是本文主要讲的内容
三. 一般开发流程(项目周期 )
在基于BDD开发模式的项目中,以Rails项目开发为例,有如下步骤:
1、 对一个项目立项后,首先进行故事分解。要对系统故事分解,要求我们做到基本的需求分析和对系统的概要设计。
2、 专注于一个用户故事,对其进行详细定义,这一阶段也就是我们编写RSpec测试用例的阶段。通过分析用户故事和用户场景的方式对系统的行为进行详细的定义,把定义写在我们的测试用例中。在这一阶段,包括了我们的传统的软件工程周期中的需求分析和详细设计阶段,需求分析体现在分析系统的行为上,详细设计体现在用例编写时需要为系统实现定义大量的接口,这一点下边细讲。
3、 对于该用户故事,实现View层:
3.1、运行RSpec测试用例,结果失败;
3.2、编码实现该view;
3.3、重新RSpec运行测试用例,通过;
3.4、重构代码;
4、 对于该用户故事,实现controller层,重复3.1-3.4的过程。
5、 对于该用户故事,实现model层,重复3.1-3.4的过程。
6、 重构三个层次的代码,完成该用户故事。
7、 重复3-6的过程,完成系统其他用户故事。
8、 系统集成,集成测试,确认测试,beta测试等。
9、 系统交付及后期维护。
这个过程图示如下:
这里强调了按照view、controller到model的顺序来做开发,这是BDD鼓励从外向里的方式来开发程序,先实现与用户直接交互的view层,然后是核心业务层controller,最后是与数据库交互的model层,BDD不但是我们开发程序中运用的一种技术,同时也可以尽早的将系统的用户接口体现出来,体现系统的商业价值,对于开发,用户与系统交互时的行为是系统的核心业务,先将用户接口开发出来,有助于我们专注于实现核心业务,而不浪费精力于其他方面。
四. 配置与Rspec实践
1.安装与配置
如果是已有项目直接在gemsfile里面配置即可如下 如(由于笔者使用的jruby版本比较低)
group :development, :test do
gem "database_cleaner"
gem "rspec-rails"
gem "cucumber-rails"
gem "webrat"
gem "rspec-mocks"
gem "spork",'~> 1.0rc'
gem "factory_girl",'~>2.6.4'
gem "factory_girl_rails",'~>1.7.0'
end
主要配置插件有
rspec-rails
cucumber-rails
factory_girl_rails(模拟大量测试数据)
在这里配置好后可直接bundle update 自动安装相关插件
当然也可以用gem install XXXXX方式安装。
最后形成的目录结构如图
小技巧 如果使用时rubymine 这个IDE,你可以利用他的tools工具选项里面bundle操作,或是quick install gem 来安装和维护插件
2. control部分测试实践(主要运用了stub的打桩技术)
代码如下
before(:each) do
@metadatum = mock_model(Metadatum)
@metadatum.stub(:subscribe_to_the_number_of).and_return("1")
@metadatum.stub(:save).and_return(true)
end
it "Get index should not nil" do
get "index"
response.should_not be_nil
assigns[:metadatas].should_not be_nil
end
首先我们可以看到一个一般Rspec测试主要用到的格式
describe “测试描述”do
befor(:each) do
每个测试用列都需要执行的内容
end
it “测试用例说明”do
具体测试代码
end
end
控制器中response的返回结果可能不同,在笔者项目中主要用到几种类型数据测试
redirect_to(重定向 )
在具体测试中我们可以这样写
response.should redirect_to(:action => :index)
对于flash数据我们要验证他的内容我们可以这样写
flash[:notice].should eq('你预计得到的结果')
对于render的数据内容你可以用render_template 来接受如下
response.should render_template (:action中用到的键 => 具体的值 )
而对于action中调用action的时候,我们为了保证系统解耦性,所以需要截获调用action和返回值,这时候我们可以用到mock
比如上面用到的
@metadatum = mock_model(Metadatum)
Metadatum.stub(:new).and_return(@metadatum)
@metadatum.stub(:subscribe_to_the_number_of).and_return("1")
@metadatum.stub(:save).and_return(true)
这几句就是我们用来模拟Metadatum这个模型的方法
3.model的测试(主要运用factory_girl构建数据技术)
对于模型的测试我们主要运用factory_girl来做大量数据模拟,具体代码如下
在..\spec\factories目录下我们主要是构建测试数据
FactoryGirl.define do
factory :metadatum do
abstract "Administrative orders"
metadata_identifier "administrative"
metadatadate_update Time.now
resource_type "About administrative orders "
upload_state Date.today
online_source "orders"
publication_data Date.today
resource_degree ""
resource_id 1
resource_title 1
verify_enable 1
end
end
在我们具体model测试中调用这个数据方法如下
..\spec\models\metadatum_rspec.rb
before(:each) do
@metadata = Factory.create(:metadatum)
end
it "This 'verify_enable' should be 0 "do
@metadata.set_resource_type(0)
expect(@metadata.resource_type).to eq(0)
end
我这里用了expect这个断言,一旦出现失败的情况,就会在测试中体现出来,当然我们也可以用should这个方法来测试,那么最后一句就该这样写
@metadata.resource_type.should == 0
五.总结
经过一段时间的学习,自己大约摸到点测试的感觉,但是需要学习的东西还很多,自己在针对模型测试,只是在今晚才刚学习了factory一点东西,还有大量的没有做到,针对view和gem测试部分还没学习到,当然自己上面的东西也不一定全面和正确,关于测试学习部分我以后也会继续维护。