Mocha 旨在用於測試替身的模擬物件或測試存根類型的單元測試,而不是假物件或測試間諜類型。儘管可以擴展 Mocha 以允許實現假貨和間諜,但我們選擇將其重點放在模擬和存根上。
使用以下命令安裝最新版本的 gem...
$ gem install mocha
注意:如果您打算將 Mocha 與 Test::Unit 或 Minitest 一起使用,則應僅在載入相關測試庫後設定 Mocha...
require 'rubygems'
gem 'mocha'
require 'test/unit'
require 'mocha/test_unit'
require 'rubygems'
gem 'mocha'
require 'minitest/autorun'
require 'mocha/minitest'
如果您使用 Bundler,請將 Mocha 包含在Gemfile
中,然後在知道測試庫已載入後設定 Mocha...
# Gemfile
gem 'mocha'
# Elsewhere after Bundler has loaded gems e.g. after `require 'bundler/setup'`
require 'test/unit'
require 'mocha/test_unit'
# Gemfile
gem 'mocha'
# Elsewhere after Bundler has loaded gems e.g. after `require 'bundler/setup'`
require 'minitest/autorun'
require 'mocha/minitest'
RSpec 包含一個摩卡轉接器。只要告訴 RSpec 你想用:mocha
來模擬:
# Gemfile in Rails app
gem 'mocha'
# Within `spec/spec_helper.rb`
RSpec . configure do | config |
config . mock_with :mocha
end
注意:不需要使用 require 語句來設定 Mocha; RSpec 自己做這件事。
# In e.g. features/support/mocha.rb
require 'mocha/api'
World ( Mocha :: API )
Around do | scenario , block |
begin
mocha_setup
block . call
mocha_verify
ensure
mocha_teardown
end
end
如果您在 Rails 應用程式中使用 Bundler 載入 Mocha,則應該手動設定 Mocha,例如在test_helper.rb
的底部。
請注意,從 Rails v4(至少)開始, ActiveSupport::TestCase
繼承自Minitest::Test
或其早期的等效項。因此,除非您明確使用 Test::Unit,否則您很可能會使用 Minitest。
# Gemfile in Rails app
gem 'mocha'
# At bottom of test_helper.rb (or at least after `require 'rails/test_help'`)
require 'mocha/minitest'
請依照 Bundler 部分中相關測試框架的說明進行操作,但確保在載入測試框架後需要相關的 Mocha 檔案( mocha/minitest
、 mocha/test_unit
或mocha/api
),例如位於test_helper.rb
或spec_helper.rb
,或者至少在需要rails/test_help
之後。
extend
類別的模組中定義原始方法的別名類別方法存根在 Ruby v1.8 中不起作用。有關此行為的範例,請參閱test/acceptance/stub_method_defined_on_module_and_aliased_test.rb
。 require 'test/unit'
require 'mocha/test_unit'
class MiscExampleTest < Test :: Unit :: TestCase
def test_mocking_a_class_method
product = Product . new
Product . expects ( :find ) . with ( 1 ) . returns ( product )
assert_equal product , Product . find ( 1 )
end
def test_mocking_an_instance_method_on_a_real_object
product = Product . new
product . expects ( :save ) . returns ( true )
assert product . save
end
def test_stubbing_instance_methods_on_real_objects
prices = [ stub ( pence : 1000 ) , stub ( pence : 2000 ) ]
product = Product . new
product . stubs ( :prices ) . returns ( prices )
assert_equal [ 1000 , 2000 ] , product . prices . collect { | p | p . pence }
end
def test_stubbing_an_instance_method_on_all_instances_of_a_class
Product . any_instance . stubs ( :name ) . returns ( 'stubbed_name' )
product = Product . new
assert_equal 'stubbed_name' , product . name
end
def test_traditional_mocking
object = mock ( 'object' )
object . expects ( :expected_method ) . with ( :p1 , :p2 ) . returns ( :result )
assert_equal :result , object . expected_method ( :p1 , :p2 )
end
def test_shortcuts
object = stub ( method1 : :result1 , method2 : :result2 )
assert_equal :result1 , object . method1
assert_equal :result2 , object . method2
end
end
class Enterprise
def initialize ( dilithium )
@dilithium = dilithium
end
def go ( warp_factor )
warp_factor . times { @dilithium . nuke ( :anti_matter ) }
end
end
require 'test/unit'
require 'mocha/test_unit'
class EnterpriseTest < Test :: Unit :: TestCase
def test_should_boldly_go
dilithium = mock ( )
dilithium . expects ( :nuke ) . with ( :anti_matter ) . at_least_once # auto-verified at end of test
enterprise = Enterprise . new ( dilithium )
enterprise . go ( 2 )
end
end
class Order
attr_accessor :shipped_on
def total_cost
line_items . inject ( 0 ) { | total , line_item | total + line_item . price } + shipping_cost
end
def total_weight
line_items . inject ( 0 ) { | total , line_item | total + line_item . weight }
end
def shipping_cost
total_weight * 5 + 10
end
class << self
def find_all
# Database.connection.execute('select * from orders...
end
def number_shipped_since ( date )
find_all . select { | order | order . shipped_on > date } . length
end
def unshipped_value
find_all . inject ( 0 ) { | total , order | order . shipped_on ? total : total + order . total_cost }
end
end
end
require 'test/unit'
require 'mocha/test_unit'
class OrderTest < Test :: Unit :: TestCase
# illustrates stubbing instance method
def test_should_calculate_shipping_cost_based_on_total_weight
order = Order . new
order . stubs ( :total_weight ) . returns ( 10 )
assert_equal 60 , order . shipping_cost
end
# illustrates stubbing class method
def test_should_count_number_of_orders_shipped_after_specified_date
now = Time . now ; week_in_secs = 7 * 24 * 60 * 60
order_1 = Order . new ; order_1 . shipped_on = now - 1 * week_in_secs
order_2 = Order . new ; order_2 . shipped_on = now - 3 * week_in_secs
Order . stubs ( :find_all ) . returns ( [ order_1 , order_2 ] )
assert_equal 1 , Order . number_shipped_since ( now - 2 * week_in_secs )
end
# illustrates stubbing instance method for all instances of a class
def test_should_calculate_value_of_unshipped_orders
Order . stubs ( :find_all ) . returns ( [ Order . new , Order . new , Order . new ] )
Order . any_instance . stubs ( :shipped_on ) . returns ( nil )
Order . any_instance . stubs ( :total_cost ) . returns ( 10 )
assert_equal 30 , Order . unshipped_value
end
end
Mocha 目前不嘗試實作線程安全。
簡短的回答是否定的。在多執行緒程式碼中,Mocha 異常可能會在執行測試的執行緒以外的執行緒中引發,因此 Mocha 異常可能無法被 Mocha 異常處理程式碼正確攔截。
也許吧,但也可能不是。部分模擬會更改ObjectSpace
中物件的狀態,該狀態在 Ruby 進程中的所有執行緒之間共享,並且對有效全域狀態的存取不同步。因此,例如,如果兩個測試同時運行,並且一個測試使用#any_instance
修改類,則兩個測試都會立即看到這些變更。
存根和期望基本上是同一件事。存根只是零次或多次呼叫的期望。 Expectation#stubs
方法是語法糖,使測試的意圖更加明確。
當對模擬物件呼叫方法時,模擬物件會從最新到最舊的順序搜尋其期望,以找到與呼叫相符的方法。呼叫後,匹配的期望可能會停止匹配進一步的呼叫。
有關更多詳細信息,請參閱Mocha::Mock
的文檔。
如果需要,Mocha 可以在以下情況下產生警告或引發異常:
有關更多詳細信息,請參閱Mocha::Configuration
的文檔。
MOCHA_OPTIONS
是一個環境變量,其值可以設定為逗號分隔的列表,以便我們可以指定多個選項,例如MOCHA_OPTIONS=debug,use_test_unit_gem
。目前僅以以下值識別並有效:
debug
:啟用偵錯模式,該模式將為每個棄用警告輸出回溯。這對於查找測試套件中已棄用的呼叫所在的位置非常有用。請參閱此貢獻者清單。
使用變更摘要更新 RELEASE.md 文件
修改lib/mocha/version.rb
中的版本
提交並推送到 GitHub
檢查 CircleCI 建置是否通過 - https://app.circleci.com/pipelines/github/freerange/mocha
產生文件:
$ MOCHA_GENERATE_DOCS=true bundle install
$ MOCHA_GENERATE_DOCS=true rake generate_docs
$ curl -u < email-address > -H ' OTP: ' https://rubygems.org/api/v1/api_key.yaml > ~ /.gem/credentials ; chmod 0600 ~ /.gem/credentials
$ rake release
[runs tests]
mocha 1.2.0 built to pkg/mocha-1.2.0.gem.
Tagged v1.2.0.
Pushed git commits and tags.
Pushed mocha 1.2.0 to rubygems.org.
Mocha 最初是從 Reevoo 的計畫中收穫的。它的語法很大程度上是基於 jMock 的語法。
© 版權所有詹姆斯·米德 2006
您可以根據與 Ruby 本身相同的條款或 MIT 授權使用、複製和重新散佈該程式庫。