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
的底部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 许可使用、复制和重新分发该库。