Mocha soll in Unit-Tests für die Typen Mock Object oder Test Stub von Test Double verwendet werden, nicht für die Typen Fake Object oder Test Spy. Obwohl es möglich wäre, Mocha zu erweitern, um die Implementierung von Fälschungen und Spionen zu ermöglichen, haben wir uns entschieden, den Fokus auf Mocks und Stubs zu belassen.
Installieren Sie die neueste Version des Gems mit dem folgenden Befehl ...
$ gem install mocha
Hinweis: Wenn Sie Mocha mit Test::Unit oder Minitest verwenden möchten, sollten Sie Mocha erst einrichten, nachdem Sie die entsprechende Testbibliothek geladen haben ...
require 'rubygems'
gem 'mocha'
require 'test/unit'
require 'mocha/test_unit'
require 'rubygems'
gem 'mocha'
require 'minitest/autorun'
require 'mocha/minitest'
Wenn Sie Bundler verwenden, fügen Sie Mocha in die Gemfile
ein und richten Sie Mocha später ein, sobald Sie wissen, dass die Testbibliothek geladen wurde ...
# 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 enthält einen Mokka-Adapter. Sagen Sie RSpec einfach, dass Sie mit :mocha
verspotten möchten:
# Gemfile in Rails app
gem 'mocha'
# Within `spec/spec_helper.rb`
RSpec . configure do | config |
config . mock_with :mocha
end
Hinweis: Es ist nicht erforderlich, eine require-Anweisung zum Einrichten von Mocha zu verwenden. RSpec erledigt dies selbst.
# 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
Wenn Sie Mocha mit Bundler in einer Rails-Anwendung laden, sollten Sie Mocha manuell einrichten, z. B. am Ende Ihrer test_helper.rb
.
Beachten Sie, dass ActiveSupport::TestCase
seit Rails v4 (mindestens) von Minitest::Test
oder seinen früheren Äquivalenten geerbt hat. Sofern Sie also nicht explizit Test::Unit verwenden, verwenden Sie wahrscheinlich Minitest.
# Gemfile in Rails app
gem 'mocha'
# At bottom of test_helper.rb (or at least after `require 'rails/test_help'`)
require 'mocha/minitest'
Befolgen Sie die Anweisungen für das entsprechende Testframework im Abschnitt Bundler, stellen Sie jedoch sicher, dass die entsprechende Mocha-Datei ( mocha/minitest
, mocha/test_unit
oder mocha/api
) erforderlich ist, nachdem das Testframework geladen wurde, z. B. am Ende von test_helper.rb
oder spec_helper.rb
oder zumindest nachdem rails/test_help
erforderlich war.
extend
der Klasse verwendet wird, in Ruby v1.8 nicht. Ein Beispiel für dieses Verhalten finden Sie 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 versucht derzeit nicht, Thread-sicher zu sein.
Die kurze Antwort ist nein. In Multithread-Code können Mocha-Ausnahmen in einem anderen Thread als dem ausgelöst werden, der den Test ausführt, und daher wird eine Mocha-Ausnahme vom Mocha-Ausnahmebehandlungscode möglicherweise nicht korrekt abgefangen.
Vielleicht, aber wahrscheinlich nicht. Durch teilweises Verspotten wird der Status von Objekten im ObjectSpace
geändert, der von allen Threads im Ruby-Prozess gemeinsam genutzt wird, und dieser Zugriff auf den effektiv globalen Status ist nicht synchronisiert. Wenn also beispielsweise zwei Tests gleichzeitig ausgeführt werden und einer #any_instance
verwendet, um eine Klasse zu ändern, werden beide Tests diese Änderungen sofort sehen.
Stubs und Erwartungen sind im Grunde dasselbe. Ein Stub ist lediglich eine Erwartung von null oder mehr Aufrufen. Die Expectation#stubs
-Methode ist syntaktischer Zucker, um die Absicht des Tests deutlicher zu machen.
Wenn eine Methode für ein Scheinobjekt aufgerufen wird, durchsucht das Scheinobjekt seine Erwartungen vom neuesten zum ältesten, um eine Methode zu finden, die dem Aufruf entspricht. Nach dem Aufruf kann es sein, dass die Übereinstimmungserwartung bei weiteren Aufrufen nicht mehr mit der Übereinstimmung übereinstimmt.
Weitere Einzelheiten finden Sie in der Dokumentation zu Mocha::Mock
.
Wenn Sie möchten, kann Mocha eine Warnung generieren oder eine Ausnahme auslösen, wenn:
Weitere Einzelheiten finden Sie in der Dokumentation zu Mocha::Configuration
.
MOCHA_OPTIONS
ist eine Umgebungsvariable, deren Wert auf eine durch Kommas getrennte Liste gesetzt werden kann, sodass wir mehrere Optionen angeben können, z. B. MOCHA_OPTIONS=debug,use_test_unit_gem
. Derzeit werden nur die folgenden Werte erkannt und wirken sich aus:
debug
: Aktiviert einen Debug-Modus, der Backtraces für jede Veraltungswarnung ausgibt. Dies ist nützlich, um herauszufinden, wo in der Testsuite sich die veralteten Aufrufe befinden.Sehen Sie sich diese Liste der Mitwirkenden an.
Aktualisieren Sie die Datei RELEASE.md mit einer Zusammenfassung der Änderungen
Erhöhen Sie die Version in lib/mocha/version.rb
Commit und Push auf GitHub
Überprüfen Sie, ob der CircleCI-Build erfolgreich ist – https://app.circleci.com/pipelines/github/freerange/mocha
Dokumentation erstellen:
$ 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.
Mokka wurde ursprünglich aus Projekten bei Reevoo geerntet. Seine Syntax basiert stark auf der von jMock.
© Copyright James Mead 2006
Sie dürfen diese Bibliothek unter den gleichen Bedingungen wie Ruby selbst oder unter der MIT-Lizenz verwenden, kopieren und weiterverbreiten.