??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美一区二区高清在线观看,日韩激情欧美,久热国产精品http://www.aygfsteel.com/lzj520/category/26946.htmlzh-cnTue, 20 Nov 2007 10:19:09 GMTTue, 20 Nov 2007 10:19:09 GMT60071719 rspec在netbeans IED 6 beta上运行时的一些问?/title><link>http://www.aygfsteel.com/lzj520/archive/2007/11/19/161635.html</link><dc:creator>lzj520</dc:creator><author>lzj520</author><pubDate>Mon, 19 Nov 2007 07:45:00 GMT</pubDate><guid>http://www.aygfsteel.com/lzj520/archive/2007/11/19/161635.html</guid><wfw:comment>http://www.aygfsteel.com/lzj520/comments/161635.html</wfw:comment><comments>http://www.aygfsteel.com/lzj520/archive/2007/11/19/161635.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lzj520/comments/commentRss/161635.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lzj520/services/trackbacks/161635.html</trackback:ping><description><![CDATA[不知是我弄错了什么地方,q是本来是q样的,在netbeans IED 6 betaq行rspecӞ假如先是先运行scaffold_resourceQ然后按照rspec官方的文档的Ҏ(gu)来安装rspec、rspec_on_railsQƈq行rspec、rspec_modelQ然而此Ӟ试默认生成的modelQ就会得到类DL错误提示Q?br /> 1.0.1/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:34:in `require': no such file to load -- E:/NetBeansProjects/RailsApplication2/spec/models/../../vendor/generators/rspec/lib/rspec_on_rails (MissingSourceFile)<br /> 此时打开spec_helper.rbQ发现rspec_on_rails的这一路径默认是不对的Q需要手工把它设|ؓ正确的\径。或者我试过把这句\径的引用直接删除掉,好像也可以?br /> <br /> 处理完这一步之后,会遇到的跟着的这样一个错误提C:<br /> spec/models/../spec_helper.rb:9: undefined local variable or method `use_transactional_fixtures=' for Spec::Runner::Context:Class (NameError)<br /> q需要你去test_helper.rb里加入一句require File.expand_path(File.dirname(__FILE__) + "/test2spec_help")Q把use_transactional_fixtures加入q来。然后在spec_helper.rb里加入require File.expand_path(File.dirname(__FILE__) + "/../test/test_helper")<br /> <br /> 然后才能正式看到1 example, 1 failureq样比较正常的提C。不知是否我操作错误Q还是什么问题,M是到了这样一q串的问? 而这个解军_法也不知是否正确 <img src ="http://www.aygfsteel.com/lzj520/aggbug/161635.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lzj520/" target="_blank">lzj520</a> 2007-11-19 15:45 <a href="http://www.aygfsteel.com/lzj520/archive/2007/11/19/161635.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>071030 一个jmock实例http://www.aygfsteel.com/lzj520/archive/2007/10/30/156839.htmllzj520lzj520Tue, 30 Oct 2007 01:18:00 GMThttp://www.aygfsteel.com/lzj520/archive/2007/10/30/156839.htmlhttp://www.aygfsteel.com/lzj520/comments/156839.htmlhttp://www.aygfsteel.com/lzj520/archive/2007/10/30/156839.html#Feedback0http://www.aygfsteel.com/lzj520/comments/commentRss/156839.htmlhttp://www.aygfsteel.com/lzj520/services/trackbacks/156839.html 首先建立试用例Q?br />

public class PlaceOrderServiceTests extends MockObjectTestCase{

 Mockery context = new Mockery();
   
    public void testUpdateRestaurant_good() throws Exception{
     //setup
     PlaceOrderService service = new PlaceOrderService();
     final RestaurantRepository restaurantRepository  =  context.mock(RestaurantRepository.class);
     final String restaurantId = "1";
     final String pendingOrderId = "1";
     //expectations
     context.checking(new Expectations(){{
      allowing(restaurantRepository).findRestaurant(restaurantId,pendingOrderId);
      }});
     //execute
     service.updateRestaurant(restaurantId,pendingOrderId);
     //verify
     context.assertIsSatisfied();
    }
}
然后分别建立相应的类和接口:

public interface RestaurantRepository {

 Restaurant findRestaurant(String restaurantId, String pendingOrderId);

}

public class Restaurant {

}

public class PlaceOrderService {

 public void updateRestaurant(String restaurantId, String pendingOrderId) {
  // TODO Auto-generated method stub
  
 }

}



lzj520 2007-10-30 09:18 发表评论
]]>
使用 RSpec q行行ؓ驱动试Q{Q?/title><link>http://www.aygfsteel.com/lzj520/archive/2007/10/23/155374.html</link><dc:creator>lzj520</dc:creator><author>lzj520</author><pubDate>Tue, 23 Oct 2007 11:01:00 GMT</pubDate><guid>http://www.aygfsteel.com/lzj520/archive/2007/10/23/155374.html</guid><wfw:comment>http://www.aygfsteel.com/lzj520/comments/155374.html</wfw:comment><comments>http://www.aygfsteel.com/lzj520/archive/2007/10/23/155374.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lzj520/comments/commentRss/155374.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lzj520/services/trackbacks/155374.html</trackback:ping><description><![CDATA[<blockquote>试热潮现在传播C Ruby ~程C֌Qƈ且愈演愈热。在q去一q里Q测试领域中最为瞩目的创新应属 RSpec 的引入和快速发展,q是一U行为驱动测试工兗通过本文了解 RSpec 如何改变Z思考测试的方式?</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES--> <p>在过dq中QY件开发h员对试的热情日渐低q同一时期出现的动态语aq没有提供编译程序来捕捉最基本的错误,q得测试变得更加重要。随着试C֌的成长,开发h员开始注意到Q除了捕?bug {最基本的优点外Q测试还h以下优势Q?/p> <ul> <li>试能够改进(zhn)的设计。进行测试的每个目标对象必须具备臛_两个客户机:生代码和测试用例。这些客h强制(zhn)对代码q行解耦。测试还鼓励开发h员用更、更单的Ҏ(gu)? <li>试减少了不必要的代码。在~写试用例Ӟ(zhn)养成了很好的测试习惯,卛_~写q行试用例所需的最代码。?zhn)抵制住了对功能进行编码的诱惑Q因为?zhn)目前q不需要它? <li>推动了测试优先开发。?zhn)~写的每个测试用例会定一个小问题。用代码解册个问题非常有用ƈ且可以推动开发。当我进行测试驱动开发时Q时间过得飞快? <li>试提供了更多的自主权。在使用试用例捕获可能的错误时Q?zhn)会发现自己非常愿意对代码q行改进?</li> </ul> <p><a name="N10062"><span id="wmqeeuq" class="atitle">试驱动的开发和 RSpec</span></a></p> <p>有关试的优Ҏ(gu)需赘述Q我向(zhn)介l一个简单的使用 RSpec 的测试驱动开发示例。RSpec 工具是一?Ruby 软g包,可以用它构徏有关(zhn)的软g的规范。该规范实际上是一个描q系l行为的试。?RSpec 的开发流E如下:</p> <ul> <li>~写一个测试。该试描述pȝ中某个较?yu)元素的行ؓ? <li>q行试。由于尚没有为系l中的相应部分构Z码,试p|。这一重要步骤测试?zhn)的测试用例,验测试用例是否在应当p|的时候失败? <li>~写_的代码,使测试通过? <li>q行试Q检验测试是否成功?</li> </ul> <p>实质上,RSpec 开发h员所做的工作是失败的试用例调试为成功的试用例。这是一个主动的q程。本文中Q我介l?RSpec 的基本用法?</p> <p>首先Q假设?zhn)已安装?Ruby ?gems。?zhn)q需要安?RSpec。输入下面的内容Q?</p> <p><code>gem install rspec</code> </p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> <p><a name="N10086"><span id="wmqeeuq" class="atitle">使用CZ</span></a></p> <p>接下来,我将逐步构徏一个状态机。我遵?TDD 规则。首先编写自q试用例Qƈ且直到测试用例需要时才编写代码。Rake 的创?Jim Weirich 认ؓq有助于角色扮演。在~写实际的生产代码时Q?zhn)希望充当一?jerk 开发h员的角色Q只完成最量的工作来使测试通过。在~写试Ӟ(zhn)则扮演试人员的角Ԍ试图为开发h员提供一些有益的帮助?/p> <p>以下的示例展CZ如何构徏一个状态机。如果?zhn)以前从未接触q状态机Q请查阅 <a >参考资?/a>。状态机h多种状态。每U状态支持可以{换状态机状态的事g。测试驱动开发入门的关键是从零入手Q尽量少C用假设条件。针Ҏ(gu)试进行程序设计?/p> <p>使用清单 1 的内容创建名?machine_spec.rb 的文件。该文g是(zhn)的规范。?zhn)q不了解 machine.rb 文g的作用,目前先创Z个空文g?/p> <br /> <a name="listing1"><strong>清单 1. 最初的 machine_spec.rb 文g </strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode"> require 'machine' </pre> </td> </tr> </tbody> </table> <br /> <p>接下来,需要运行测试。始l通过输入 <code>spec machine_spec.rb</code> q行试。清?2 展示了预料之中的试p|Q?/p> <br /> <a name="listing2"><strong>清单 2. q行I的规范</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">~/rspec batate$ spec machine_spec.rb /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require': no such file to load -- machine (LoadError) from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' from ./state_machine_spec.rb:1 from ... </pre> </td> </tr> </tbody> </table> <br /> <p>在测试驱动开发中Q?zhn)需要进行增量开发,因此在进行下一ơ开发前Q需要先解决此次试出现的问题。现在,我将扮演 jerk 开发h员的角色Q即只完成满_用程序运行所需的最工作量。我创Z个名?machine.rb 的空文gQɋ试通过。我现在可以以逸待劻I试通过而我几乎没做M事情?/p> <p>l箋角色扮演。我现在扮演一个烦w的试人员Q促?jerk 开发h员做些实际的工作。我编码以下规范,需要?<code>Machine</code> c,如清?3 所C:</p> <br /> <a name="listing3"><strong>清单 3. 初始规范</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">require 'machine' describe Machine do before :each do @machine = Machine end end </pre> </td> </tr> </tbody> </table> <br /> <p>该规范描qC目前不存在?<code>Machine</code> cR?code>describe</code> Ҏ(gu)提供?RSpec 描述Q?zhn)传入测试类的名U和包含实际规范的代码块。通常Q测试用例需要执行一定数量的讄工作。在 RSpec 中,由 <code>before</code> Ҏ(gu)完成q些讄工作。?zhn)?<code>before</code> Ҏ(gu)传递一个可选的标志和一个代码块。代码块中包含设|工作。标志确?RSpec 执行代码块的频率。默认的标志?<code>:each</code>Q表C?RSpec 在每次试之前调用 set up 代码块。?zhn)也可以指?<code>:all</code>Q表C?RSpec 在执行所有测试之前只调用一?<code>before</code> 代码块。?zhn)应该始终使?<code>:each</code>Q各个试彼此独立?</p> <p>输入 <code>spec</code> q行试Q如清单 4 所C: </p> <br /> <a name="listing4"><strong>清单 4. 存在性测试失?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">~/rspec batate$ spec machine_spec.rb ./machine_spec.rb:3: uninitialized constant Machine (NameError) </pre> </td> </tr> </tbody> </table> <br /> <p>现在Q烦w的试人员要促?jerk 开发h员做点什么了 ?jerk 开发h员现在需要创建某个类。对我来_是修复试出现的错误。在 <code>machine.rb</code> 中,我输入最量的代码,如清?5 所C:</p> <br /> <a name="listing5"><strong>清单 5. 创徏初始 Machine c?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">class Machine end</pre> </td> </tr> </tbody> </table> <br /> <p>保存文gQ然后运行测试。毫无疑问,清单 6 昄的测试报告没有出现错误:</p> <br /> <a name="listing6"><strong>清单 6. 试 Machine 是否存在</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">~/rspec batate$ spec machine_spec.rb Finished in 5.0e-06 seconds 0 examples, 0 failures </pre> </td> </tr> </tbody> </table> <br /> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> <p><a name="N10116"><span id="wmqeeuq" class="atitle">~写行ؓ</span></a></p> <p>现在Q我可以开始实现更多的行ؓ。我知道Q所有状态机必须在某些初始状态下启动。目前我q不是很清楚如何设计q个行ؓQ因此我先编写一个非常简单的试Q首先假?<code>state</code> Ҏ(gu)会返?<code>:initial</code> 标志。我?<code>machine_spec.rb</code> q行修改q运行测试,如清?7 所C:</p> <br /> <a name="listing7"><strong>清单 7. 实现初始状态ƈq行试</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">require 'machine' describe Machine do before :each do @machine = Machine.new end it "should initially have a state of :initial" do @machine.state.should == :initial end end ~/rspec batate$ spec machine_spec.rb F 1) NoMethodError in 'Machine should initially have a state of :initial' undefined method `state' for #<Machine:0x10c7f8c> ./machine_spec.rb:9: Finished in 0.005577 seconds 1 example, 1 failure </pre> </td> </tr> </tbody> </table> <br /> <p>注意q条规则Q?code> it "should initially have a state of :initial" do @machine.state.should == :initial end</code>。首先注意到q条规则读v来像是一个英文句子。删除标点,得?<code>it should initially have a state of initial</code>。然后会注意到这条规则ƈ不像是典型的面向对象代码。它实不是。?zhn)现在有一个方法,UCؓ <code>it</code>。该Ҏ(gu)h一个用引hh的字W串参数和一个代码块。字W串应该描述试需求。最后,<code>do</code> ?<code>end</code> 之间的代码块包含试用例的代码?</p> <p>可以看到Q测试进度划分得很细。这些微的步骤产生的收益却很大。它们我能够改q测试密度,提供旉供我思考期望的行ؓ以及实现行ؓ所需?API。这些步骤还能我在开发期间跟t代码覆盖情况,从而构建更加丰富的规范?/p> <p>q种风格的测试具有双重作用:试实现q在试的同时构建需求设计文档。稍后,我将通过试用例构徏一个需求列表?/p> <p>我用最单的方式修复了测试,q回 <code>:initial</code>Q如清单 8 所C:</p> <br /> <a name="listing8"><strong>清单 8. 指定初始状?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">class Machine def state :initial end end </pre> </td> </tr> </tbody> </table> <br /> <p>当查看实现时Q?zhn)可能会放声大W或感觉受到了愚弄。对于测试驱动开发,(zhn)必ȝ微改变一下思考方式。?zhn)的目标ƈ不是~写最l的生代码Q至现在不是。?zhn)的目标是使测试通过。当掌握以这U方式工作时Q?zhn)可能会发现新的实玎ͼq且~写的代码要q远于采用 TDD 时编写的代码?/p> <p>下一步是q行代码Q查看它是否通过试Q?/p> <br /> <a name="listing9"><strong>清单 9. q行初始状态测?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">~/rspec batate$ spec machine_spec.rb . Finished in 0.005364 seconds 1 example, 0 failures</pre> </td> </tr> </tbody> </table> <br /> <p>׃旉思考一下这个通过试的P代。如果查看代码的话,(zhn)可能会觉得气馁。因为ƈ没有取得什么进展。如果查看整个P代,看到更多内容:(zhn)捕获了一个重要需求ƈ~写试用例实现需求。作Z名程序员Q我的第一个行为测试帮助我明确了开发过E。因为实现细节随着试的进行越来越清晰?/p> <p>现在Q我可以实现一个更健壮的状态实现。具体来Ԍ我需要处理状态机的多个状态。我需要创Z个新的规则获取有效状态列表。像以前一P我将q行试q查看是否通过?/p> <br /> <a name="listing10"><strong>清单 10. 实现有效状态规?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode"> it "should remember a list of valid states" do @machine.states = [:shopping, :checking_out] @machine.states.should = [:shopping, :checking_out] end run test(note: failing first verifies test) ~/rspec batate$ spec machine_spec.rb .F 1) NoMethodError in 'Machine should remember a list of valid states' undefined method `states=' for #<Machine:0x10c7154> ./machine_spec.rb:13: Finished in 0.005923 seconds 2 examples, 1 failure</pre> </td> </tr> </tbody> </table> <br /> <p>在清?10 中,出现了一?RSpec 形式的断a。该断言?<code>should</code> Ҏ(gu)开始,然后d了一些比较关pR?code>should</code> Ҏ(gu)对应用程序进行某U观察。工作中的应用程序应该以某种方式q行?code>should</code> Ҏ(gu)很好地捕获了q种需求。在本例中,我的状态机应该记忆两种不同的状态?/p> <p>现在Q应该添加一个实例变量来实际记忆状态。像以往一P我在修改代码后运行测试用例,q观察测试是否成功?/p> <br /> <a name="listing11"><strong>清单 11. 创徏一个属性以记忆状?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">class Machine attr_accessor :states def state :initial end end ~/rspec batate$ spec machine_spec.rb .. Finished in 0.00606 seconds 2 examples, 0 failures</pre> </td> </tr> </tbody> </table> <br /> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> <p><a name="N10199"><span id="wmqeeuq" class="atitle">驱动重构</span></a></p> <p>此时Q我q不惛_定将 <code>:initial</code> 状态称为状态机的第一个状态。相反,我更希望W一个状态是状态数l中的第一个元素。我对状态机的理解在不断演变。这U现象ƈ不少见。测试驱动开发经常迫使我重新考虑之前的假设。由于我已经通过试用例捕获了早期需求,我可以轻村֜对代码进行重构。在本例中,重构是对代码进行调_使其更好地工作?/p> <p>修改W一个测试,使其如清?12 所C,q运行测试:</p> <br /> <a name="listing12"><strong>清单 12. 初始状态应该ؓ指定的第一个状?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">it "should initially have a state of the first state" do @machine.states = [:shopping, :checking_out] @machine.state.should == :shopping end ~/rspec batate$ spec machine_spec.rb F. 1) 'Machine should initially have a state of the first state' FAILED expected :shopping, got :initial (using ==) ./machine_spec.rb:10: Finished in 0.005846 seconds 2 examples, 1 failure</pre> </td> </tr> </tbody> </table> <br /> <p>可以q样_试用例起到作用了,因ؓ它运行失败,因此我现在需要修改代码以使其工作。显而易见,我的d是使测试通过。我喜欢q种试目的Q因为我的测试用例正在驱动我q行设计。我把初始状态传递给 <code>new</code> Ҏ(gu)。我对实现E作修改Q以W合修改后的规范Q如清单 13 所C?/p> <br /> <a name="listing13"><strong>清单 13. 指定初始状?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">start to fix it class Machine attr_accessor :states attr_reader :state def initialize(states) @states = states @state = @states[0] end end ~/rspec batate$ spec machine_spec.rb 1) ArgumentError in 'Machine should initially have a state of the first state' wrong number of arguments (0 for 1) ./machine_spec.rb:5:in `initialize' ./machine_spec.rb:5:in `new' ./machine_spec.rb:5: 2) ArgumentError in 'Machine should remember a list of valid states' wrong number of arguments (0 for 1) ./machine_spec.rb:5:in `initialize' ./machine_spec.rb:5:in `new' ./machine_spec.rb:5: Finished in 0.006391 seconds 2 examples, 2 failures</pre> </td> </tr> </tbody> </table> <br /> <p>现在Q测试出C一些错误。我扑ֈ了实C的一?bug。测试用例不再用正的接口Q因为我没有把初始状态传递给状态机。可以看刎ͼ试用例已经起到了保护作用。我q行了较大的更改Q测试就发现?bug。我们需要对试q行重构以匹配新的接口,初始状态列表传递给 <code>new</code> Ҏ(gu)。在q里我ƈ没有重复初始化代码,而是其攄?<code>before</code> Ҏ(gu)中,如清?14 所C:</p> <br /> <a name="listing14"><strong>清单 14. ?“before” 中初始化状态机 </strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">require 'machine' describe Machine do before :each do @machine = Machine.new([:shopping, :checking_out]) end it "should initially have a state of the first state" do @machine.state.should == :shopping end it "should remember a list of valid states" do @machine.states.should == [:shopping, :checking_out] end end ~/rspec batate$ spec machine_spec.rb .. Finished in 0.005542 seconds 2 examples, 0 failures</pre> </td> </tr> </tbody> </table> <br /> <p>状态机开始逐渐成型。代码仍然有一些问题,但是正在向良好的方向演化。我开始对状态机q行一些{换。这些{换将促代码实际记忆当前状态?/p> <p>试用例促我全面地思?API 的设计。我需要知道如何表CZ件和转换。首先,我将使用一个散列表表示转换Q而没有用成熟的面向对象实现。随后,试需求可能会要求我修改假设条Ӟ但是目前Q我仍然保持q种单性。清?15 昄了修改后的代码:</p> <br /> <a name="listing15"><strong>清单 15. d事g和{?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">remember events... change before conditions require 'machine' describe Machine do before :each do @machine = Machine.new([:shopping, :checking_out]) @machine.events = {:checkout => {:from => :shopping, :to => :checking_out}} end it "should initially have a state of the first state" do @machine.state.should == :shopping end it "should remember a list of valid states" do @machine.states.should == [:shopping, :checking_out] end it "should remember a list of events with transitions" do @machine.events.should == {:checkout => {:from => :shopping, :to => :checking_out}} end end ~/rspec batate$ spec machine_spec.rb FFF 1) NoMethodError in 'Machine should initially have a state of the first state' undefined method `events=' for #<Machine:0x10c6f38> ./machine_spec.rb:6: 2) NoMethodError in 'Machine should remember a list of valid states' undefined method `events=' for #z7lt;Machine:0x10c5afc> ./machine_spec.rb:6: 3) NoMethodError in 'Machine should remember a list of events with transitions' undefined method `events=' for #<Machine:0x10c4a58> ./machine_spec.rb:6: Finished in 0.006597 seconds 3 examples, 3 failures</pre> </td> </tr> </tbody> </table> <br /> <p>׃新的试代码位于 <code>before</code> 中,我的三个测试分解开来。尽如此,清单 16 中展C的试非常Ҏ(gu)修复。我添加另一个访问程序:</p> <br /> <a name="listing16"><strong>清单 16. 记忆事g</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">class Machine attr_accessor :states, :events attr_reader :state def initialize(states) @states = states @state = @states[0] end end ~/rspec batate$ spec machine_spec.rb ... Finished in 0.00652 seconds 3 examples, 0 failures test</pre> </td> </tr> </tbody> </table> <br /> <p>试全部通过。我得到了一个能正常q行的状态机。接下来的几个测试将使它更加完善?/p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> <p><a name="N101FD"><span id="wmqeeuq" class="atitle">接近真实的应用程?/span></a></p> <p>目前为止Q我所做的不过是触发了一ơ状态{换,但是我已l做好了所有基工作。我得到了一l需求。我q构Z一l测试。我的代码可以ؓ状态机提供使用的数据。此Ӟ理单个状态机转换仅表CZơ简单的转换Q因此我添加如清单 17 所C的试Q?/p> <br /> <a name="listing17"><strong>清单 17. 构徏状态机的状态{?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">it "should transition to :checking_out upon #trigger(:checkout) event " do @machine.trigger(:checkout) @machine.state.should == :checking_out end ~/rspec batate$ spec machine_spec.rb ...F 1) NoMethodError in 'Machine should transition to :checking_out upon #trigger(:checkout) event ' undefined method `trigger' for #<Machine:0x10c4d00> ./machine_spec.rb:24: Finished in 0.006153 seconds 4 examples, 1 failure</pre> </td> </tr> </tbody> </table> <br /> <p>我需要抵制快速构建大量功能的诱惑。我应该只编写少量代码,只要使测试通过卛_。清?18 展示的P代将表示 API 和需求。这p够了Q?/p> <br /> <a name="listing18"><strong>清单 18. 定义 trigger Ҏ(gu)</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">def trigger(event) @state = :checking_out end ~/rspec batate$ spec machine_spec.rb .... Finished in 0.005959 seconds 4 examples, 0 failures</pre> </td> </tr> </tbody> </table> <br /> <p>q里出现了一个有的Ҏ(gu)。在~写代码Ӟ我两ơ都弄错了这个简单的Ҏ(gu)。第一ơ我q回?<code>:checkout</code>Q第二次我将状态设|ؓ <code>:checkout</code> 而不?<code>:checking_out</code>。在试中用较?yu)的步骤可以为我节省大量旉Q因为测试用例ؓ我捕Lq些错误在将来的开发中很难捕获到。本文的最后一个步骤是实际执行一ơ状态机转换。在W一个示例中Q我q不兛_实际的机器状态是什么样子的。我仅仅是根据事件进行盲目{换,而不考虑状态?/p> <p>两节点的状态机无法执行q个操作Q我需要在W三个节点中构徏。我没有使用已有?<code>before</code> Ҏ(gu)Q只是在新状态中d另外的状态。我在试用例中进行两ơ{换,以确保状态机能够正确地执行{换,如清?19 所C:</p> <br /> <a name="listing19"><strong>清单 19. 实现W一ơ{?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">it "should transition to :success upon #trigger(:accept_card)" do @machine.events = { :checkout => {:from => :shopping, :to => :checking_out}, :accept_card => {:from => :checking_out, :to => :success} } @machine.trigger(:checkout) @machine.state.should == :checking_out @machine.trigger(:accept_card) @machine.state.should == :success end ~/rspec batate$ spec machine_spec.rb ....F 1) 'Machine should transition to :success upon #trigger(:accept_card)' FAILED expected :success, got :checking_out (using ==) ./machine_spec.rb:37: Finished in 0.007564 seconds 5 examples, 1 failure</pre> </td> </tr> </tbody> </table> <br /> <p>q个试?<code>:checkout</code> ?<code>:accept_card</code> 事g建立新的状态机。在处理{ևӞ我选择使用两个事g而不是一个,q样可以防止发生双命令。签Z码可以确保状态机在签Z前处?<code>shopping</code> 状态。第一ơ签出首先将状态机?<code>shopping</code> 转换?<code>checking_out</code>。测试用例通过触发 <code>checkout</code> ?<code>accept_card</code> 事g实现两个转换Qƈ在调用事件之后检验事件状态是否正。与预期一P试用例p| ?我ƈ没有~写处理多个转换的触发器Ҏ(gu)。代码修正包含一行非帔R要的代码。清?20 展示了状态机的核心: </p> <br /> <a name="listing20"><strong>清单 20. 状态机的核?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">def trigger(event) @state = events[event][:to] end ~/rspec batate$ spec machine_spec.rb ..... Finished in 0.006511 seconds 5 examples, 0 failures</pre> </td> </tr> </tbody> </table> <br /> <p>试可以q行。这些粗p的代码W一ơ演变ؓ真正可以UC为状态机的东ѝ但是这q远q不够。目前,状态机~Z严密性。不状态如何,状态机都会触发事g。例如,当处?<code>shopping</code> 状态时Q触?<code>:accept_card</code> q不会{换ؓ <code>:success</code> 状态。?zhn)只能够?<code>:checking_out</code> 状态触?<code>:accept_card</code>。在~程术语中,<code>trigger</code> Ҏ(gu)的范围应针对事g。我编写一个测试来解决问题Q然后修?bug。我编写一个负试Qnegative testQ,xa一个不应该出现的行为,如清?21 所C:</p> <br /> <a name="listing21"><strong>清单 21: 负测?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">it "should not transition from :shopping to :success upon :accept_card" do @machine.events = { :checkout => {:from => :shopping, :to => :checking_out}, :accept_card => {:from => :checking_out, :to => :success} } @machine.trigger(:accept_card) @machine.state.should_not == :success end rspec batate$ spec machine_spec.rb .....F 1) 'Machine should not transition from :shopping to :success upon :accept_card' FAILED expected not == :success, got :success ./machine_spec.rb:47: Finished in 0.006582 seconds 6 examples, 1 failure</pre> </td> </tr> </tbody> </table> <br /> <p>现在可以再次q行试Q其中一个测试如预期一栯行失败。修复代码同样只有一行,如清?22 所C:</p> <br /> <a name="listing22"><strong>清单 22. 修复 trigger 中的范围问题 </strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">def trigger(event) @state = events[event][:to] if state == events[event][:from] end rspec batate$ spec machine_spec.rb ...... Finished in 0.006873 seconds 6 examples, 0 failures</pre> </td> </tr> </tbody> </table> <br /> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> <p><a name="N1029C"><span id="wmqeeuq" class="atitle">l合代码</span></a></p> <p>现在Q我h一个可单运行的状态机。无Z哪方面来_它都不是一个完的E序。它q具有下面这些问题:</p> <ul> <li>状态散列实际上不具备Q何功能。我应该Ҏ(gu)状态对事g及其转换q行验证Q或者将所有状态集中v来。后l需求很可能会要求这样做? <li>某个既定事g只能存在于一个状态中。这U限制ƈ不合理。例如,<code>submit</code> ?<code>cancel</code> 事g可能需要处于多个状态? <li>代码q不具备明显的面向对象特征。ؓ佉K|保持简单,我将大量数据|入散列中。后l的q代会进一步驱动设计,使其朝面向对象设计方向发展?</li> </ul> <p>但是Q?zhn)q可以看刎ͼq个状态机已经能够满一些需求了。我q具备一个描q系l行为的文档Q这是进行一pd试的好L。每个测试用例都支持pȝ的一个基本需求。事实上Q通过q行 <code>spec machine_spec.rb --format specdoc</code>Q?zhn)可以查看ql规范组成的基本报告Q如清单 23 所C:</p> <br /> <a name="listing23"><strong>清单 23. 查看规范</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">spec machine_spec.rb --format specdoc Machine - should initially have a state of the first state - should remember a list of valid states - should remember a list of events with transitions - should transition to :checking_out upon #trigger(:checkout) event - should transition to :success upon #trigger(:accept_card) - should not transition from :shopping to :success upon :accept_card Finished in 0.006868 seconds</pre> </td> </tr> </tbody> </table> <br /> <p>试驱动Ҏ(gu)q不适合所有hQ但是越来越多的人开始用这U技术,使用它构建具有灵zL和适应性的高质量代码,q且Ҏ(gu)试从头构徏代码。当Ӟ(zhn)也可以通过其他框架Q如 test_unitQ获得相同的优点。RSpec q提供了优秀的实现方法。这U新试框架的一大亮点就是代码的表示。新手尤其可以从q种行ؓ驱动的测试方法中受益。请试使用该框架ƈ告诉我?zhn)的感受?/p> <img src ="http://www.aygfsteel.com/lzj520/aggbug/155374.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lzj520/" target="_blank">lzj520</a> 2007-10-23 19:01 <a href="http://www.aygfsteel.com/lzj520/archive/2007/10/23/155374.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">䴨</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">뽭</a>| <a href="http://" target="_blank">ʯ</a>| <a href="http://" target="_blank">Ͻ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">̨</a>| <a href="http://" target="_blank">԰</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank">ͨ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɳ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">°Ͷ</a>| <a href="http://" target="_blank">׳</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ͻ</a>| <a href="http://" target="_blank">½</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ĭ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ԭ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ľ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">մ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>