Mocha est destiné à être utilisé dans les tests unitaires pour les types Mock Object ou Test Stub de Test Double, et non pour les types Fake Object ou Test Spy. Bien qu'il soit possible d'étendre Mocha pour permettre la mise en œuvre de contrefaçons et d'espions, nous avons choisi de le concentrer sur les moqueries et les talons.
Installez la dernière version de la gemme avec la commande suivante...
$ gem install mocha
Remarque : Si vous avez l'intention d'utiliser Mocha avec Test::Unit ou Minitest, vous ne devez configurer Mocha qu'après avoir chargé la bibliothèque de tests appropriée...
require 'rubygems'
gem 'mocha'
require 'test/unit'
require 'mocha/test_unit'
require 'rubygems'
gem 'mocha'
require 'minitest/autorun'
require 'mocha/minitest'
Si vous utilisez Bundler, incluez Mocha dans le Gemfile
, puis configurez Mocha plus tard une fois que vous savez que la bibliothèque de test a été chargée...
# 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 comprend un adaptateur moka. Dites simplement à RSpec que vous voulez vous moquer avec :mocha
:
# Gemfile in Rails app
gem 'mocha'
# Within `spec/spec_helper.rb`
RSpec . configure do | config |
config . mock_with :mocha
end
Remarque : Il n'est pas nécessaire d'utiliser une instruction require pour configurer Mocha ; RSpec le fait lui-même.
# 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
Si vous chargez Mocha à l'aide de Bundler dans une application Rails, vous devez configurer Mocha manuellement, par exemple au bas de votre test_helper.rb
.
Notez que depuis Rails v4 (au moins), ActiveSupport::TestCase
a hérité de Minitest::Test
ou de ses équivalents antérieurs. Ainsi, à moins que vous n'utilisiez explicitement Test::Unit, vous utiliserez probablement Minitest.
# Gemfile in Rails app
gem 'mocha'
# At bottom of test_helper.rb (or at least after `require 'rails/test_help'`)
require 'mocha/minitest'
Suivez les instructions pour le framework de test concerné dans la section Bundler, mais assurez-vous que le fichier Mocha approprié ( mocha/minitest
, mocha/test_unit
ou mocha/api
) est requis après le chargement du framework de test, par exemple au bas de test_helper.rb
ou spec_helper.rb
, ou au moins après que rails/test_help
ait été requis.
extend
la classe ne fonctionnait pas dans Ruby v1.8. Voir test/acceptance/stub_method_defined_on_module_and_aliased_test.rb
pour un exemple de ce comportement. 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 ne tente actuellement pas d'être thread-safe.
La réponse courte est non. Dans le code multithread, les exceptions Mocha peuvent être générées dans un thread autre que celui qui exécute le test et donc une exception Mocha peut ne pas être correctement interceptée par le code de gestion des exceptions Mocha.
Peut-être, mais probablement pas. La moquerie partielle modifie l'état des objets dans l' ObjectSpace
qui est partagé entre tous les threads du processus Ruby et cet accès à ce qui est effectivement un état global n'est pas synchronisé. Ainsi, par exemple, si deux tests s'exécutent simultanément et que l'un d'entre eux utilise #any_instance
pour modifier une classe, les deux tests verront ces modifications immédiatement.
Les talons et les attentes sont fondamentalement la même chose. Un stub est simplement une attente de zéro ou plusieurs invocations. La méthode Expectation#stubs
est du sucre syntaxique pour rendre l'intention du test plus explicite.
Lorsqu'une méthode est invoquée sur un objet fictif, l'objet fictif recherche parmi ses attentes, de la plus récente à la plus ancienne, pour en trouver une qui correspond à l'invocation. Après l’invocation, l’attente de correspondance peut cesser de correspondre à d’autres invocations.
Consultez la documentation de Mocha::Mock
pour plus de détails.
Si vous le souhaitez, Mocha peut générer un avertissement ou déclencher une exception lorsque :
Consultez la documentation de Mocha::Configuration
pour plus de détails.
MOCHA_OPTIONS
est une variable d'environnement dont la valeur peut être définie sur une liste séparée par des virgules, afin que nous puissions spécifier plusieurs options, par exemple MOCHA_OPTIONS=debug,use_test_unit_gem
. Seules les valeurs suivantes sont actuellement reconnues et ont un effet :
debug
: active un mode de débogage qui affichera des traces pour chaque avertissement de dépréciation. Ceci est utile pour trouver où se trouvent les appels obsolètes dans la suite de tests.Voir cette liste de contributeurs.
Mettez à jour le fichier RELEASE.md avec un résumé des modifications
Augmentez la version dans lib/mocha/version.rb
Validez et poussez vers GitHub
Vérifiez que la version CircleCI est réussie - https://app.circleci.com/pipelines/github/freerange/mocha
Générer de la documentation :
$ 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.
Le moka a été initialement récolté dans le cadre de projets chez Reevoo. Sa syntaxe est fortement basée sur celle de jMock.
© Droits d'auteur James Mead 2006
Vous pouvez utiliser, copier et redistribuer cette bibliothèque selon les mêmes conditions que Ruby lui-même ou sous la licence MIT.