From a72bca82301bc4851f40945f85711f5cefd10178 Mon Sep 17 00:00:00 2001 From: utilum Date: Mon, 23 Jul 2018 14:16:45 +0300 Subject: Add method_call_assertions and use them instead of Mocha Six Mocha calls prove quite resistant to Minitestification. For example, if we replace ``` ActiveRecord::Associations::HasManyAssociation .any_instance .expects(:reader) .never ``` with `assert_not_called`, Minitest wisely raises ``` NameError: undefined method `reader' for class `ActiveRecord::Associations::HasManyAssociation' ``` as `:reader` comes from a deeply embedded abstract class, `ActiveRecord::Associations::CollectionAssociation`. This patch tackles this difficulty by adding `ActiveSupport::Testing::MethodCallAsserts#assert_called_on_instance_of` which injects a stubbed method into `klass`, and verifies the number of times it is called, similar to `assert_called`. It also adds a convenience method, `assert_not_called_on_instance_of`, mirroring `assert_not_called`. It uses the new method_call_assertions to replace the remaining Mocha calls in `ActiveRecord` tests. [utilum + bogdanvlviv + kspath] --- .../testing/method_call_assertions.rb | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'activesupport/lib/active_support/testing/method_call_assertions.rb') diff --git a/activesupport/lib/active_support/testing/method_call_assertions.rb b/activesupport/lib/active_support/testing/method_call_assertions.rb index c6358002ea..fdc70e1cd3 100644 --- a/activesupport/lib/active_support/testing/method_call_assertions.rb +++ b/activesupport/lib/active_support/testing/method_call_assertions.rb @@ -35,6 +35,35 @@ module ActiveSupport assert_called(object, method_name, message, times: 0, &block) end + # TODO: No need to resort to #send once support for Ruby 2.4 is + # dropped. + def assert_called_on_instance_of(klass, method_name, message = nil, times: 1, returns: nil) + times_called = 0 + klass.send(:define_method, "stubbed_#{method_name}") do |*| + times_called += 1 + + returns + end + + klass.send(:alias_method, "original_#{method_name}", method_name) + klass.send(:alias_method, method_name, "stubbed_#{method_name}") + + yield + + error = "Expected #{method_name} to be called #{times} times, but was called #{times_called} times" + error = "#{message}.\n#{error}" if message + + assert_equal times, times_called, error + ensure + klass.send(:alias_method, method_name, "original_#{method_name}") + klass.send(:undef_method, "original_#{method_name}") + klass.send(:undef_method, "stubbed_#{method_name}") + end + + def assert_not_called_on_instance_of(klass, method_name, message = nil, &block) + assert_called_on_instance_of(klass, method_name, message, times: 0, &block) + end + def stub_any_instance(klass, instance: klass.new) klass.stub(:new, instance) { yield instance } end -- cgit v1.2.3