RubyMotion 指南:測試

翻譯:@shiweifu
本文連接:http://segmentfault.com/blog/shiweifu
原文連接:http://rubymotion-tutorial.com/8-testing/
目標讀者:["想了解RubyMotion開發模式", "想學習RubyMotion", "對移動端測試感興趣"]
翻譯者按:測試是移動開發的一個痛點。這篇文章講述了使用RubyMotion如何進行有效的測試,能夠看出相對於原生開發環境的測試,簡化不少。這部分也是RubyMoiton的一大特點。segmentfault


除了語法不一樣,你可能以爲 RubyMotion 不過是提供了一條使用 Ruby 語法來編寫 Cocoa 程序的方式。和使用 Objective-C 來實現一樣的功能相比,並沒有特殊之處。本章將介紹 RubyMotion 中獨有的特性。windows

自動化測試是屌炸天的事兒。屌在哪?它能使你的程序更加健壯,經過一些測試代碼,能讓你及時發現問題所在,是否是很棒?ruby

是的,你們都認爲測試是個好東西,但事實上大多數工程師並不能堅持寫測試。它不能讓你有足夠的成就感,不是能和其餘人吹噓的牛逼特性或者性能提高。但它是一種保障,特別是項目常常改變,它能讓你知道你的代碼究竟可不可用。app

接下來咱們將瞭解 RubyMotion 中的測試,簡單編寫,覆蓋度高。ide

在 Ruby 社區,你們都很重視測試,Ruby 的測試相對 iOS App,也相對簡潔。若是要在iOS 中實現自動化測試,每每須要藉助第三方庫或者使用JavaScript。RubyMotion 的測試庫要好用的多。性能

到底有多屌?學習

Unit Testing

使用 motion create Tests 命令新建一個項目而後cd進去。咱們討論裏面的spec文件夾。測試

這個文件夾裏有一個名爲./spec/main_spec.rb的文件,這是建立項目的時候自動生成的。在 RubyMotion 的測試工做的時候,它會加載這個文件夾裏面的*.rb文件。咱們來看下這個文件的內容:ui

describe "Application 'Tests'" do
  before do
    @app = UIApplication.sharedApplication
  end

  it "has one window" do
    @app.windows.size.should == 1
  end
end

能夠看到一個簡單的表達式:@app.windows.size.should == 1,它的意思看起來是若是.size不爲1,就測試失敗。spa

.should 支持如下的判斷類型:

@app.nil?.should == false

[1,2,3].should.not == [1,2,3,4]

@model.id.should == example_id

describeit 組成了一個用來實現測試的結構。在上面的這個describe結構中,傳達了兩個意思:"[Test that] Application",被測試對象有一Window。一個describe結構中能夠包含多個itit中又能夠包含多個測試斷言。你若是喜歡的話,也能夠寫多個describe

每個將被測試的內容都會先執行before中的內容。應該把一些初始化的代碼丟到這裏。

接下來在終端中,運行rake spec,看看測試的結果。

image

仍是掛了……提示說沒有找到window。讓咱們在AppDelegate中修復:

class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.applicationFrame)
    @window.makeKeyAndVisible
    true
  end
end

再執行一次rake spec,此次正確了:

image

咦,彷佛已經經過自動化測試解決了一個Bug,希望是真的解決了吧。

咱們已經看到了如何去檢查一個對象的屬性,這頗有用但還不夠。有時候咱們會觸發事件,好比咱們敲擊了一個按鈕,它調用了一個內部方法,這種狀況下,咱們要測試須要去手動調用這個方法,而後進行測試……事實上有更好的作法。

Funcational Testing

RubyMotion 對 Funcational Testing 有着很好的支持,好比你想測試觸發 UI 事件,如TapSwipe 而後檢查它的結果,你不用去button.callback.call,你能夠用等效的方法:tap button,測試用例很整潔,對不對?

Funcational Testing雖然屌屌的,但它的侷限是它只能測試一個UIViewController。因此像pushpop這種就無能爲力了。須要注意。

要接着跑通這個例子,咱們須要一個UIViewController的子類,建立./app/ButtonController.rb,而後增長一個按鈕和回調事件。代碼以下:

class ButtonController < UIViewController
  def viewDidLoad
    super

    @button = UIButton.buttonWithType(UIButtonTypeRoundedRect)
    @button.setTitle("Test me title!", forState:UIControlStateNormal)
    @button.accessibilityLabel = "Test me!"
    @button.sizeToFit
    @button.frame = CGRect.new([10, 70], @button.frame.size)
    self.view.addSubview(@button)

    @button.addTarget(self, action:'tapped', forControlEvents:UIControlEventTouchUpInside)
  end

  def tapped
    p "I'm tapped!"
    @was_tapped = true
  end
end

標準的代碼,除了accessibilityLabel。這是每一個View都包含的一個String類型屬性。當使用VoiceOver功能的時候,系統依賴這個屬性(因此別隨便設置這個屬性的值)。爲啥咱們會提到這一點?由於 RubyMotion 的Funcational Testing就依賴這個屬性。因此確保要測試的View已經設置好這個屬性。

最後,咱們把ControllerAppDelegate關聯起來:

def application(application, didFinishLaunchingWithOptions:launchOptions)
  @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.applicationFrame)
  @window.makeKeyAndVisible

  @view_controller = ButtonController.alloc.initWithNibName(nil, bundle:nil)
  @window.rootViewController = @view_controller

  true
end

你可使用rake執行一下,看看在你觸發按鈕事件的時候終端有沒有輸出I'm tapped!。接下來咱們寫測試代碼,看看變量是否真的被賦值。

main_spec.rb,添加describe塊及代碼:

describe "button controller" do
  tests ButtonController

  it "changes instance variable when button is tapped" do
    tap 'Test me!'
    controller.instance_variable_get("@was_tapped").should == true
  end
end

讓咱們來看看有啥新東西。

tests <class>鏈接咱們的describe,指定UIViewController。它的行爲很清晰:將要測試的UIViewController放在了一個新的UIWindow中。咱們能使用self.windowself.controller訪問其。這樣作也確保了被測試的Controller不會被幹擾。

tap能夠替換成flickdragpinch_closepinch_openrotate對應相應的行爲。查看RubyMotion's full documentation具體的細節。

rake spec,它已經能正常工做啦:

2 specifications (2 requirements), 0 failures, 0 errors

總結

咱們看到了在RubyMotion中編寫測試是多麼的簡單。若是你以前由於繁瑣不寫測試,如今沒理由懶惰了。

咱們學到了啥?

  • RubyMotion加載測試用例從./spec目錄。
  • 測試用例包含在describeit中,後面跟隨着標籤,用來標識和組織。
  • 使用 <any object>.should 進行斷言。例:greeting.should == "hello"
  • UIViewControllers能夠進行funcational。 tests,能夠模擬一些像tappinch觸發事件。在你的describe代碼塊中,使用tests <controller class>去使用這些特性。
  • tap <accessibility label>是訪問View的accessibilityLabel屬性。
相關文章
相關標籤/搜索