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();
}
}
鐒跺悗鍒嗗埆寤虹珛鐩稿簲鐨勭被鍜屾帴鍙o細(xì)
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
}
}
鍦ㄨ繃鍘誨崄騫翠腑錛岃蔣浠跺紑鍙戜漢鍛樺嫻嬭瘯鐨勭儹鎯呮棩娓愪綆榪楓傚悓涓鏃舵湡鍑虹幇鐨勫姩鎬佽璦騫舵病鏈夋彁渚涚紪璇戠▼搴忔潵鎹曟崏鏈鍩烘湰鐨勯敊璇紝榪欎嬌寰楁祴璇曞彉寰楁洿鍔犻噸瑕併傞殢鐫嫻嬭瘯紺懼尯鐨勬垚闀匡紝寮鍙戜漢鍛樺紑濮嬫敞鎰忓埌錛岄櫎浜嗘崟鑾?bug 絳夋渶鍩烘湰鐨勪紭鐐瑰錛屾祴璇曡繕鍏鋒湁浠ヤ笅浼樺娍錛?/p>
鏈夊叧嫻嬭瘯鐨勪紭鐐規(guī)棤闇璧樿堪錛屾垜灝嗗悜鎮(zhèn)ㄤ粙緇嶄竴涓畝鍗曠殑浣跨敤 RSpec 鐨勬祴璇曢┍鍔ㄥ紑鍙戠ず渚嬨俁Spec 宸ュ叿鏄竴涓?Ruby 杞歡鍖咃紝鍙互鐢ㄥ畠鏋勫緩鏈夊叧鎮(zhèn)ㄧ殑杞歡鐨勮鑼冦傝瑙勮寖瀹為檯涓婃槸涓涓弿榪扮郴緇熻涓虹殑嫻嬭瘯銆備嬌鐢?RSpec 鐨勫紑鍙戞祦紼嬪涓嬶細(xì)
瀹炶川涓婏紝RSpec 寮鍙戜漢鍛樻墍鍋氱殑宸ヤ綔灝辨槸灝嗗け璐ョ殑嫻嬭瘯鐢ㄤ緥璋冭瘯涓烘垚鍔熺殑嫻嬭瘯鐢ㄤ緥銆傝繖鏄竴涓富鍔ㄧ殑榪囩▼銆傛湰鏂囦腑錛屾垜灝嗕粙緇?RSpec 鐨勫熀鏈敤娉曘?
棣栧厛錛屽亣璁炬?zhèn)ㄥ凡瀹夎浜?Ruby 鍜?gems銆傛?zhèn)q橀渶瑕佸畨瑁?RSpec銆傝緭鍏ヤ笅闈㈢殑鍐呭錛?
gem install rspec
![]() ![]() |
鎺ヤ笅鏉ワ紝鎴戝皢閫愭鏋勫緩涓涓姸鎬佹満銆傛垜灝嗛伒寰?TDD 瑙勫垯銆傞鍏堢紪鍐欒嚜宸辯殑嫻嬭瘯鐢ㄤ緥錛屽茍涓旂洿鍒版祴璇曠敤渚嬮渶瑕佹椂鎵嶇紪鍐欎唬鐮併俁ake 鐨勫垱寤鴻?Jim Weirich 璁や負(fù)榪欐湁鍔╀簬瑙掕壊鎵紨銆傚湪緙栧啓瀹為檯鐨勭敓浜т唬鐮佹椂錛屾?zhèn)ㄥ笇鏈涘厖褰撲竴鍥?jerk 寮鍙戜漢鍛樼殑瑙掕壊錛屽彧瀹屾垚鏈灝戦噺鐨勫伐浣滄潵浣挎祴璇曢氳繃銆傚湪緙栧啓嫻嬭瘯鏃訛紝鎮(zhèn)ㄥ垯鎵紨嫻嬭瘯浜哄憳鐨勮鑹詫紝璇曞浘涓哄紑鍙戜漢鍛樻彁渚涗竴浜涙湁鐩婄殑甯姪銆?/p>
浠ヤ笅鐨勭ず渚嬪睍紺轟簡濡備綍鏋勫緩涓涓姸鎬佹満銆傚鏋滄?zhèn)ㄤ互鍓嶄粠鏈帴瑙q囩姸鎬佹満錛岃鏌ラ槄 鍙傝冭祫鏂?/a>銆傜姸鎬佹満鍏鋒湁澶氱鐘舵併傛瘡縐嶇姸鎬佹敮鎸佸彲浠ヨ漿鎹㈢姸鎬佹満鐘舵佺殑浜嬩歡銆傛祴璇曢┍鍔ㄥ紑鍙戝叆闂ㄧ殑鍏抽敭灝辨槸浠庨浂鍏ユ墜錛屽敖閲忓皯鍦頒嬌鐢ㄥ亣璁炬潯浠躲傞拡瀵規(guī)祴璇曡繘琛岀▼搴忚璁°?/p>
浣跨敤娓呭崟 1 鐨勫唴瀹瑰垱寤哄悕涓?machine_spec.rb 鐨勬枃浠躲傝鏂囦歡灝辨槸鎮(zhèn)ㄧ殑瑙勮寖銆傛?zhèn)q樹笉浜嗚В machine.rb 鏂囦歡鐨勪綔鐢紝鐩墠鍏堝垱寤轟竴涓┖鏂囦歡銆?/p>
娓呭崟 1. 鏈鍒濈殑 machine_spec.rb 鏂囦歡
require 'machine' |
鎺ヤ笅鏉ワ紝闇瑕佽繍琛屾祴璇曘傚緇堥氳繃杈撳叆 spec machine_spec.rb
榪愯嫻嬭瘯銆傛竻鍗?2 灞曠ず浜嗛鏂欎箣涓殑嫻嬭瘯澶辮觸錛?/p>
娓呭崟 2. 榪愯絀虹殑瑙勮寖
~/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 ... |
鍦ㄦ祴璇曢┍鍔ㄥ紑鍙戜腑錛屾?zhèn)ㄩ渶瑕佽繘琛屽閲忓紑鍙戯紝鍥犳鍦ㄨ繘琛屼笅涓嬈″紑鍙戝墠錛岄渶瑕佸厛瑙e喅姝ゆ嫻嬭瘯鍑虹幇鐨勯棶棰樸傜幇鍦紝鎴戝皢鎵紨 jerk 寮鍙戜漢鍛樼殑瑙掕壊錛屽嵆鍙畬鎴愭弧瓚沖簲鐢ㄧ▼搴忚繍琛屾墍闇鐨勬渶灝戝伐浣滈噺銆傛垜灝嗗垱寤轟竴涓悕涓?machine.rb 鐨勭┖鏂囦歡錛屼嬌嫻嬭瘯閫氳繃銆傛垜鐜板湪鍙互浠ラ稿緟鍔籌紝嫻嬭瘯閫氳繃鑰屾垜鍑犱箮娌″仛浠諱綍浜嬫儏銆?/p>
緇х畫瑙掕壊鎵紨銆傛垜鐜板湪鎵紨涓涓儲韜佺殑嫻嬭瘯浜哄憳錛屼績浣?jerk 寮鍙戜漢鍛樺仛浜涘疄闄呯殑宸ヤ綔銆傛垜灝嗙紪鐮佷互涓嬭鑼冿紝闇瑕佷嬌鐢?Machine
綾伙紝濡傛竻鍗?3 鎵紺猴細(xì)
require 'machine' describe Machine do before :each do @machine = Machine end end |
璇ヨ鑼冩弿榪頒簡鐩墠灝氫笉瀛樺湪鐨?Machine
綾匯?code>describe 鏂規(guī)硶鎻愪緵浜?RSpec 鎻忚堪錛屾?zhèn)畣浼犲叆娴嬭瘯绫荤殑鍚嵖U板拰鍖呭惈瀹為檯瑙勮寖鐨勪唬鐮佸潡銆傞氬父錛屾祴璇曠敤渚嬮渶瑕佹墽琛屼竴瀹氭暟閲忕殑璁劇疆宸ヤ綔銆傚湪 RSpec 涓紝灝嗙敱 before
鏂規(guī)硶瀹屾垚榪欎簺璁劇疆宸ヤ綔銆傛?zhèn)ㄥ?before
鏂規(guī)硶浼犻掍竴涓彲閫夌殑鏍囧織鍜屼竴涓唬鐮佸潡銆備唬鐮佸潡涓寘鍚緗伐浣溿傛爣蹇楃‘瀹?RSpec 鎵ц浠g爜鍧楃殑棰戠巼銆傞粯璁ょ殑鏍囧織涓?:each
錛岃〃紺?RSpec 灝嗗湪姣忔嫻嬭瘯涔嬪墠璋冪敤 set up 浠g爜鍧椼傛?zhèn)ㄤ篃鍙互鎸囧?:all
錛岃〃紺?RSpec 鍦ㄦ墽琛屾墍鏈夋祴璇曚箣鍓嶅彧璋冪敤涓嬈?before
浠g爜鍧椼傛?zhèn)ㄥ簲璇ュ缁堜娇鐢?:each
錛屼嬌鍚勪釜嫻嬭瘯褰兼鐙珛銆?
杈撳叆 spec
榪愯嫻嬭瘯錛屽娓呭崟 4 鎵紺猴細(xì)
~/rspec batate$ spec machine_spec.rb ./machine_spec.rb:3: uninitialized constant Machine (NameError) |
鐜板湪錛岀儲韜佺殑嫻嬭瘯浜哄憳瑕佷績浣?jerk 寮鍙戜漢鍛樺仛鐐逛粈涔堜簡 鈥?jerk 寮鍙戜漢鍛樼幇鍦ㄩ渶瑕佸垱寤烘煇涓被銆傚鎴戞潵璇達(dá)紝灝辨槸淇嫻嬭瘯鍑虹幇鐨勯敊璇傚湪 machine.rb
涓紝鎴戣緭鍏ユ渶灝戦噺鐨勪唬鐮侊紝濡傛竻鍗?5 鎵紺猴細(xì)
class Machine end |
淇濆瓨鏂囦歡錛岀劧鍚庤繍琛屾祴璇曘傛鏃犵枒闂紝娓呭崟 6 鏄劇ず鐨勬祴璇曟姤鍛婃病鏈夊嚭鐜伴敊璇細(xì)
~/rspec batate$ spec machine_spec.rb Finished in 5.0e-06 seconds 0 examples, 0 failures |
![]() ![]() |
鐜板湪錛屾垜鍙互寮濮嬪疄鐜版洿澶氱殑琛屼負(fù)銆傛垜鐭ラ亾錛屾墍鏈夌姸鎬佹満蹇呴』鍦ㄦ煇浜涘垵濮嬬姸鎬佷笅鍚姩銆傜洰鍓嶆垜榪樹笉鏄緢娓呮濡備綍璁捐榪欎釜琛屼負(fù)錛屽洜姝ゆ垜鍏堢紪鍐欎竴涓潪甯哥畝鍗曠殑嫻嬭瘯錛岄鍏堝亣璁?state
鏂規(guī)硶浼?xì)杩斿?:initial
鏍囧織銆傛垜瀵?machine_spec.rb
榪涜淇敼騫惰繍琛屾祴璇曪紝濡傛竻鍗?7 鎵紺猴細(xì)
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 |
娉ㄦ剰榪欐潯瑙勫垯錛?code> it "should initially have a state of :initial" do @machine.state.should == :initial end銆傞鍏堟敞鎰忓埌榪欐潯瑙勫垯璇昏搗鏉ュ儚鏄竴涓嫳鏂囧彞瀛愩傚垹闄ゆ爣鐐癸紝灝嗗緱鍒?it should initially have a state of initial
銆傜劧鍚庝細(xì)娉ㄦ剰鍒拌繖鏉¤鍒欏茍涓嶅儚鏄吀鍨嬬殑闈㈠悜瀵硅薄浠g爜銆傚畠紜疄涓嶆槸銆傛?zhèn)ㄧ幇鍦ㄦ湁涓涓柟娉曪紝縐頒負(fù) it
銆傝鏂規(guī)硶鍏鋒湁涓涓嬌鐢ㄥ紩鍙鋒嫭璧鋒潵鐨勫瓧絎︿覆鍙傛暟鍜屼竴涓唬鐮佸潡銆傚瓧絎︿覆搴旇鎻忚堪嫻嬭瘯闇姹傘傛渶鍚庯紝do
鍜?end
涔嬮棿鐨勪唬鐮佸潡鍖呭惈嫻嬭瘯鐢ㄤ緥鐨勪唬鐮併?
鍙互鐪嬪埌錛屾祴璇曡繘搴﹀垝鍒嗗緱寰堢粏銆傝繖浜涘井灝忕殑姝ラ浜х敓鐨勬敹鐩婂嵈寰堝ぇ銆傚畠浠嬌鎴戣兘澶熸敼榪涙祴璇曞瘑搴︼紝鎻愪緵鏃墮棿渚涙垜鎬濊冩湡鏈涚殑琛屼負(fù)浠ュ強(qiáng)瀹炵幇琛屼負(fù)鎵闇鐨?API銆傝繖浜涙楠よ繕鑳戒嬌鎴戝湪寮鍙戞湡闂磋窡韙唬鐮佽鐩栨儏鍐碉紝浠庤屾瀯寤烘洿鍔犱赴瀵岀殑瑙勮寖銆?/p>
榪欑椋庢牸鐨勬祴璇曞叿鏈夊弻閲嶄綔鐢細(xì)嫻嬭瘯瀹炵幇騫跺湪嫻嬭瘯鐨勫悓鏃舵瀯寤洪渶姹傝璁℃枃妗c傜◢鍚庯紝鎴戝皢閫氳繃嫻嬭瘯鐢ㄤ緥鏋勫緩涓涓渶姹傚垪琛ㄣ?/p>
鎴戜嬌鐢ㄦ渶綆鍗曠殑鏂瑰紡淇浜嗘祴璇曪紝榪斿洖 :initial
錛屽娓呭崟 8 鎵紺猴細(xì)
class Machine def state :initial end end |
褰撴煡鐪嬪疄鐜版椂錛屾?zhèn)ㄥ彲鑳戒細(xì)鏀惧0澶ЫW戞垨鎰熻鍙楀埌浜嗘剼寮勩傚浜庢祴璇曢┍鍔ㄥ紑鍙戯紝鎮(zhèn)ㄥ繀欏葷◢寰敼鍙樹竴涓嬫濊冩柟寮忋傛?zhèn)ㄧ殑鐩爣迤堜笉鏄~栧啓鏈緇堢殑鐢熶駭浠g爜錛岃嚦灝戠幇鍦ㄤ笉鏄傛?zhèn)ㄧ殑鐩爣鏄娇娴嬭瘯閫氳繃銆傚綋鎺屾彙浠ヨ繖縐嶆柟寮忓伐浣滄椂錛屾?zhèn)ㄥ彲鑳戒細(xì)鍙戠幇鏂扮殑瀹炵帋图岒q朵笖緙栧啓鐨勪唬鐮佽榪滆繙灝戜簬閲囩敤 TDD 鏃剁紪鍐欑殑浠g爜銆?/p>
涓嬩竴姝ユ槸榪愯浠g爜錛屾煡鐪嬪畠鏄惁閫氳繃嫻嬭瘯錛?/p>
娓呭崟 9. 榪愯鍒濆鐘舵佹祴璇?/strong>
~/rspec batate$ spec machine_spec.rb . Finished in 0.005364 seconds 1 example, 0 failures |
鑺變簺鏃墮棿鎬濊冧竴涓嬭繖涓氳繃嫻嬭瘯鐨勮凱浠c傚鏋滄煡鐪嬩唬鐮佺殑璇濓紝鎮(zhèn)ㄥ彲鑳戒細(xì)瑙夊緱姘旈銆傚洜涓哄茍娌℃湁鍙栧緱浠涔堣繘灞曘傚鏋滄煡鐪嬫暣涓凱浠o紝灝嗙湅鍒版洿澶氬唴瀹癸細(xì)鎮(zhèn)ㄦ崟鑾蜂簡涓涓噸瑕侀渶姹傚茍緙栧啓嫻嬭瘯鐢ㄤ緥瀹炵幇闇姹傘備綔涓轟竴鍚嶇▼搴忓憳錛屾垜鐨勭涓涓涓烘祴璇曞府鍔╂垜鏄庣‘浜嗗紑鍙戣繃紼嬨傚洜涓哄疄鐜扮粏鑺傞殢鐫嫻嬭瘯鐨勮繘琛岃秺鏉ヨ秺娓呮櫚銆?/p>
鐜板湪錛屾垜鍙互瀹炵幇涓涓洿鍋ュ.鐨勭姸鎬佸疄鐜般傚叿浣撴潵璁詫紝鎴戦渶瑕佸鐞嗙姸鎬佹満鐨勫涓姸鎬併傛垜闇瑕佸垱寤轟竴涓柊鐨勮鍒欒幏鍙栨湁鏁堢姸鎬佸垪琛ㄣ傚儚浠ュ墠涓鏍鳳紝鎴戝皢榪愯嫻嬭瘯騫舵煡鐪嬫槸鍚﹂氳繃銆?/p>
娓呭崟 10. 瀹炵幇鏈夋晥鐘舵佽鑼?/strong>
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 |
鍦ㄦ竻鍗?10 涓紝鍑虹幇浜嗕竴涓?RSpec 褰㈠紡鐨勬柇璦銆傝鏂█浠?should
鏂規(guī)硶寮濮嬶紝鐒跺悗娣誨姞浜嗕竴浜涙瘮杈冨叧緋匯?code>should 鏂規(guī)硶瀵瑰簲鐢ㄧ▼搴忚繘琛屾煇縐嶈瀵熴傚伐浣滀腑鐨勫簲鐢ㄧ▼搴忓簲璇ヤ互鏌愮鏂瑰紡榪愯銆?code>should 鏂規(guī)硶寰堝ソ鍦版崟鑾蜂簡榪欑闇姹傘傚湪鏈緥涓紝鎴戠殑鐘舵佹満搴旇璁板繂涓ょ涓嶅悓鐨勭姸鎬併?/p>
鐜板湪錛屽簲璇ユ坊鍔犱竴涓疄渚嬪彉閲忔潵瀹為檯璁板繂鐘舵併傚儚浠ュ線涓鏍鳳紝鎴戝湪淇敼浠g爜鍚庤繍琛屾祴璇曠敤渚嬶紝騫惰瀵熸祴璇曟槸鍚︽垚鍔熴?/p>
娓呭崟 11. 鍒涘緩涓涓睘鎬т互璁板繂鐘舵?/strong>
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 |
![]() ![]() |
姝ゆ椂錛屾垜騫朵笉鎯沖喅瀹氬皢 :initial
鐘舵佺О涓虹姸鎬佹満鐨勭涓涓姸鎬併傜浉鍙嶏紝鎴戞洿甯屾湜絎竴涓姸鎬佹槸鐘舵佹暟緇勪腑鐨勭涓涓厓绱犮傛垜瀵圭姸鎬佹満鐨勭悊瑙e湪涓嶆柇婕斿彉銆傝繖縐嶇幇璞″茍涓嶅皯瑙併傛祴璇曢┍鍔ㄥ紑鍙戠粡甯歌揩浣挎垜閲嶆柊鑰冭檻涔嬪墠鐨勫亣璁俱傜敱浜庢垜宸茬粡閫氳繃嫻嬭瘯鐢ㄤ緥鎹曡幏浜嗘棭鏈熼渶姹傦紝鎴戝彲浠ヨ交鏉懼湴瀵逛唬鐮佽繘琛岄噸鏋勩傚湪鏈緥涓紝閲嶆瀯灝辨槸瀵逛唬鐮佽繘琛岃皟鏁達(dá)紝浣垮叾鏇村ソ鍦板伐浣溿?/p>
淇敼絎竴涓祴璇曪紝浣垮叾濡傛竻鍗?12 鎵紺猴紝騫惰繍琛屾祴璇曪細(xì)
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 |
鍙互榪欐牱璇達(dá)紝嫻嬭瘯鐢ㄤ緥璧峰埌浣滅敤浜嗭紝鍥犱負(fù)瀹冭繍琛屽け璐ワ紝鍥犳鎴戠幇鍦ㄩ渶瑕佷慨鏀逛唬鐮佷互浣垮叾宸ヤ綔銆傛樉鑰屾槗瑙侊紝鎴戠殑浠誨姟灝辨槸浣挎祴璇曢氳繃銆傛垜鍠滄榪欑嫻嬭瘯鐩殑錛屽洜涓烘垜鐨勬祴璇曠敤渚嬫鍦ㄩ┍鍔ㄦ垜榪涜璁捐銆傛垜灝嗘妸鍒濆鐘舵佷紶閫掔粰 new
鏂規(guī)硶銆傛垜灝嗗瀹炵幇紼嶄綔淇敼錛屼互絎﹀悎淇敼鍚庣殑瑙勮寖錛屽娓呭崟 13 鎵紺恒?/p>
娓呭崟 13. 鎸囧畾鍒濆鐘舵?/strong>
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 |
鐜板湪錛屾祴璇曞嚭鐜頒簡涓浜涢敊璇傛垜鎵懼埌浜嗗疄鐜頒腑鐨勪竴浜?bug銆傛祴璇曠敤渚嬩笉鍐嶄嬌鐢ㄦ紜殑鎺ュ彛錛屽洜涓烘垜娌℃湁鎶婂垵濮嬬姸鎬佷紶閫掔粰鐘舵佹満銆傚彲浠ョ湅鍒幫紝嫻嬭瘯鐢ㄤ緥宸茬粡璧峰埌浜嗕繚鎶や綔鐢ㄣ傛垜榪涜浜嗚緝澶х殑鏇存敼錛屾祴璇曞氨鍙戠幇浜?bug銆傛垜浠渶瑕佸嫻嬭瘯榪涜閲嶆瀯浠ュ尮閰嶆柊鐨勬帴鍙o紝灝嗗垵濮嬬姸鎬佸垪琛ㄤ紶閫掔粰 new
鏂規(guī)硶銆傚湪榪欓噷鎴戝茍娌℃湁閲嶅鍒濆鍖栦唬鐮侊紝鑰屾槸灝嗗叾鏀劇疆鍦?before
鏂規(guī)硶涓紝濡傛竻鍗?14 鎵紺猴細(xì)
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 |
鐘舵佹満寮濮嬮愭笎鎴愬瀷銆備唬鐮佷粛鐒舵湁涓浜涢棶棰橈紝浣嗘槸姝e湪鍚戣壇濂界殑鏂瑰悜婕斿寲銆傛垜灝嗗紑濮嬪鐘舵佹満榪涜涓浜涜漿鎹€傝繖浜涜漿鎹㈠皢淇冧嬌浠g爜瀹為檯璁板繂褰撳墠鐘舵併?/p>
嫻嬭瘯鐢ㄤ緥淇冧嬌鎴戝叏闈㈠湴鎬濊?API 鐨勮璁°傛垜闇瑕佺煡閬撳浣曡〃紺轟簨浠跺拰杞崲銆傞鍏堬紝鎴戝皢浣跨敤涓涓暎鍒楄〃琛ㄧず杞崲錛岃屾病鏈変嬌鐢ㄦ垚鐔熺殑闈㈠悜瀵硅薄瀹炵幇銆傞殢鍚庯紝嫻嬭瘯闇姹傚彲鑳戒細(xì)瑕佹眰鎴戜慨鏀瑰亣璁炬潯浠訛紝浣嗘槸鐩墠錛屾垜浠嶇劧淇濇寔榪欑綆鍗曟с傛竻鍗?15 鏄劇ず浜嗕慨鏀瑰悗鐨勪唬鐮侊細(xì)
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 |
鐢變簬鏂扮殑嫻嬭瘯浠g爜浣嶄簬 before
涓紝灝嗘垜鐨勪笁涓祴璇曞垎瑙e紑鏉ャ傚敖綆″姝わ紝娓呭崟 16 涓睍紺虹殑嫻嬭瘯闈炲父瀹規(guī)槗淇銆傛垜灝嗘坊鍔犲彟涓涓闂▼搴忥細(xì)
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 |
嫻嬭瘯鍏ㄩ儴閫氳繃銆傛垜寰楀埌浜嗕竴涓兘姝e父榪愯鐨勭姸鎬佹満銆傛帴涓嬫潵鐨勫嚑涓祴璇曞皢浣垮畠鏇村姞瀹屽杽銆?/p>
![]() ![]() |
鐩墠涓烘錛屾垜鎵鍋氱殑涓嶈繃鏄Е鍙戜簡涓嬈$姸鎬佽漿鎹紝浣嗘槸鎴戝凡緇忓仛濂戒簡鎵鏈夊熀紜宸ヤ綔銆傛垜寰楀埌浜嗕竴緇勯渶姹傘傛垜榪樻瀯寤轟簡涓緇勬祴璇曘傛垜鐨勪唬鐮佸彲浠ヤ負(fù)鐘舵佹満鎻愪緵浣跨敤鐨勬暟鎹傛鏃訛紝綆$悊鍗曚釜鐘舵佹満杞崲浠呰〃紺轟竴嬈$畝鍗曠殑杞崲錛屽洜姝ゆ垜灝嗘坊鍔犲娓呭崟 17 鎵紺虹殑嫻嬭瘯錛?/p>
娓呭崟 17. 鏋勫緩鐘舵佹満鐨勭姸鎬佽漿鎹?/strong>
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 |
鎴戦渶瑕佹姷鍒跺揩閫熸瀯寤哄ぇ閲忓姛鑳界殑璇辨儜銆傛垜搴旇鍙紪鍐欏皯閲忎唬鐮侊紝鍙浣挎祴璇曢氳繃鍗沖彲銆傛竻鍗?18 灞曠ず鐨勮凱浠e皢琛ㄧず API 鍜岄渶姹傘傝繖灝辮凍澶熶簡錛?/p>
娓呭崟 18. 瀹氫箟 trigger 鏂規(guī)硶
def trigger(event) @state = :checking_out end ~/rspec batate$ spec machine_spec.rb .... Finished in 0.005959 seconds 4 examples, 0 failures |
榪欓噷鍑虹幇浜嗕竴涓湁瓚g殑杈規(guī)敞銆傚湪緙栧啓浠g爜鏃訛紝鎴戜袱嬈¢兘寮勯敊浜嗚繖涓畝鍗曠殑鏂規(guī)硶銆傜涓嬈℃垜榪斿洖浜?:checkout
錛涚浜屾鎴戝皢鐘舵佽緗負(fù) :checkout
鑰屼笉鏄?:checking_out
銆傚湪嫻嬭瘯涓嬌鐢ㄨ緝?yōu)畯鐨勬楠ゅ彲浠ヤ负鎴戣妭鐪佸ぇ閲忔棄櫁村Q屽洜涓烘祴璇曠敤渚嬩負(fù)鎴戞崟鑾風(fēng)殑榪欎簺閿欒鍦ㄥ皢鏉ョ殑寮鍙戜腑寰堥毦鎹曡幏鍒般傛湰鏂囩殑鏈鍚庝竴涓楠ゆ槸瀹為檯鎵ц涓嬈$姸鎬佹満杞崲銆傚湪絎竴涓ず渚嬩腑錛屾垜騫朵笉鍏沖績瀹為檯鐨勬満鍣ㄧ姸鎬佹槸浠涔堟牱瀛愮殑銆傛垜浠呬粎鏄牴鎹簨浠惰繘琛岀洸鐩漿鎹紝鑰屼笉鑰冭檻鐘舵併?/p>
涓よ妭鐐圭殑鐘舵佹満鏃犳硶鎵ц榪欎釜鎿嶄綔錛屾垜闇瑕佸湪絎笁涓妭鐐逛腑鏋勫緩銆傛垜娌℃湁浣跨敤宸叉湁鐨?before
鏂規(guī)硶錛屽彧鏄湪鏂扮姸鎬佷腑娣誨姞鍙﹀鐨勭姸鎬併傛垜灝嗗湪嫻嬭瘯鐢ㄤ緥涓繘琛屼袱嬈¤漿鎹紝浠ョ‘淇濈姸鎬佹満鑳藉姝g‘鍦版墽琛岃漿鎹紝濡傛竻鍗?19 鎵紺猴細(xì)
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 |
榪欎釜嫻嬭瘯灝嗕嬌鐢?:checkout
鍜?:accept_card
浜嬩歡寤虹珛鏂扮殑鐘舵佹満銆傚湪澶勭悊絳懼嚭鏃訛紝鎴戦夋嫨浣跨敤涓や釜浜嬩歡鑰屼笉鏄竴涓紝榪欐牱鍙互闃叉鍙戠敓鍙屽懡浠ゃ傜鍑轟唬鐮佸彲浠ョ‘淇濈姸鎬佹満鍦ㄧ鍑轟箣鍓嶅浜?shopping
鐘舵併傜涓嬈$鍑洪鍏堝皢鐘舵佹満浠?shopping
杞崲涓?checking_out
銆傛祴璇曠敤渚嬮氳繃瑙﹀彂 checkout
鍜?accept_card
浜嬩歡瀹炵幇涓や釜杞崲錛屽茍鍦ㄨ皟鐢ㄤ簨浠朵箣鍚庢楠屼簨浠剁姸鎬佹槸鍚︽紜備笌棰勬湡涓鏍鳳紝嫻嬭瘯鐢ㄤ緥澶辮觸 鈥?鎴戝茍娌℃湁緙栧啓澶勭悊澶氫釜杞崲鐨勮Е鍙戝櫒鏂規(guī)硶銆備唬鐮佷慨姝e寘鍚竴琛岄潪甯擱噸瑕佺殑浠g爜銆傛竻鍗?20 灞曠ず浜嗙姸鎬佹満鐨勬牳蹇冿細(xì)
def trigger(event) @state = events[event][:to] end ~/rspec batate$ spec machine_spec.rb ..... Finished in 0.006511 seconds 5 examples, 0 failures |
嫻嬭瘯鍙互榪愯銆傝繖浜涚矖緋欑殑浠g爜絎竴嬈℃紨鍙樹負(fù)鐪熸鍙互縐頒箣涓虹姸鎬佹満鐨勪笢瑗褲備絾鏄繖榪樿繙榪滀笉澶熴傜洰鍓嶏紝鐘舵佹満緙轟箯涓ュ瘑鎬с備笉綆$姸鎬佸浣曪紝鐘舵佹満閮戒細(xì)瑙﹀彂浜嬩歡銆備緥濡傦紝褰撳浜?shopping
鐘舵佹椂錛岃Е鍙?:accept_card
騫朵笉浼?xì)铦{鎹負(fù) :success
鐘舵併傛?zhèn)ㄥ彧鑳藉浠?:checking_out
鐘舵佽Е鍙?:accept_card
銆傚湪緙栫▼鏈涓紝trigger
鏂規(guī)硶鐨勮寖鍥村簲閽堝浜嬩歡銆傛垜灝嗙紪鍐欎竴涓祴璇曟潵瑙e喅闂錛岀劧鍚庝慨澶?bug銆傛垜灝嗙紪鍐欎竴涓礋嫻嬭瘯錛坣egative test錛夛紝鍗蟲柇璦涓涓笉搴旇鍑虹幇鐨勮涓猴紝濡傛竻鍗?21 鎵紺猴細(xì)
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 |
鐜板湪鍙互鍐嶆榪愯嫻嬭瘯錛屽叾涓竴涓祴璇曞棰勬湡涓鏍瘋繍琛屽け璐ャ備慨澶嶄唬鐮佸悓鏍峰彧鏈変竴琛岋紝濡傛竻鍗?22 鎵紺猴細(xì)
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 |
![]() ![]() |
鐜板湪錛屾垜鍏鋒湁涓涓彲綆鍗曡繍琛岀殑鐘舵佹満銆傛棤璁轟粠鍝柟闈㈡潵璇達(dá)紝瀹冮兘涓嶆槸涓涓畬緹庣殑紼嬪簭銆傚畠榪樺叿鏈変笅闈㈣繖浜涢棶棰橈細(xì)
submit
鍜?cancel
浜嬩歡鍙兘闇瑕佸浜庡涓姸鎬併?
浣嗘槸錛屾?zhèn)q樺彲浠ョ湅鍒幫紝榪欎釜鐘舵佹満宸茬粡鑳藉婊¤凍涓浜涢渶姹備簡銆傛垜榪樺叿澶囦竴涓弿榪扮郴緇熻涓虹殑鏂囨。錛岃繖鏄繘琛屼竴緋誨垪嫻嬭瘯鐨勫ソ璧風(fēng)偣銆傛瘡涓祴璇曠敤渚嬮兘鏀寔緋葷粺鐨勪竴涓熀鏈渶姹傘備簨瀹炰笂錛岄氳繃榪愯 spec machine_spec.rb --format specdoc
錛屾?zhèn)ㄥ彲浠ユ煡鐪嬬斵q郴緇熻鑼冪粍鎴愮殑鍩烘湰鎶ュ憡錛屽娓呭崟 23 鎵紺猴細(xì)
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 |
嫻嬭瘯椹卞姩鏂規(guī)硶騫朵笉閫傚悎鎵鏈変漢錛屼絾鏄秺鏉ヨ秺澶氱殑浜哄紑濮嬩嬌鐢ㄨ繖縐嶆妧鏈紝浣跨敤瀹冩瀯寤哄叿鏈夌伒媧繪у拰閫傚簲鎬х殑楂樿川閲忎唬鐮侊紝騫朵笖鏍規(guī)嵁嫻嬭瘯浠庡ご鏋勫緩浠g爜銆傚綋鐒訛紝鎮(zhèn)ㄤ篃鍙互閫氳繃鍏朵粬妗嗘灦錛堝 test_unit錛夎幏寰楃浉鍚岀殑浼樼偣銆俁Spec 榪樻彁渚涗簡浼樼鐨勫疄鐜版柟娉曘傝繖縐嶆柊嫻嬭瘯妗嗘灦鐨勪竴澶т寒鐐瑰氨鏄唬鐮佺殑琛ㄧず銆傛柊鎵嬪挨鍏跺彲浠ヤ粠榪欑琛屼負(fù)椹卞姩鐨勬祴璇曟柟娉曚腑鍙楃泭銆傝灝濊瘯浣跨敤璇ユ鏋跺茍鍛婅瘔鎴戞?zhèn)ㄧ殑鎰熷彈銆?/p>