aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
authorutilum <oz@utilum.com>2018-07-23 14:16:45 +0300
committerutilum <oz@utilum.com>2018-08-13 13:05:14 +0200
commita72bca82301bc4851f40945f85711f5cefd10178 (patch)
treeba8388ed23ee929a0ae1ccfa9a105c0da0ced76c /activesupport
parentbef6c8bbe8faf2cf3538e9611eaddc0b2da4d038 (diff)
downloadrails-a72bca82301bc4851f40945f85711f5cefd10178.tar.gz
rails-a72bca82301bc4851f40945f85711f5cefd10178.tar.bz2
rails-a72bca82301bc4851f40945f85711f5cefd10178.zip
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]
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/lib/active_support/testing/method_call_assertions.rb29
-rw-r--r--activesupport/test/testing/method_call_assertions_test.rb83
2 files changed, 112 insertions, 0 deletions
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
diff --git a/activesupport/test/testing/method_call_assertions_test.rb b/activesupport/test/testing/method_call_assertions_test.rb
index 0500e47def..92ad72fb83 100644
--- a/activesupport/test/testing/method_call_assertions_test.rb
+++ b/activesupport/test/testing/method_call_assertions_test.rb
@@ -91,6 +91,65 @@ class MethodCallAssertionsTest < ActiveSupport::TestCase
end
end
+ def test_assert_called_on_instance_of_with_defaults_to_expect_once
+ assert_called_on_instance_of Level, :increment do
+ @object.increment
+ end
+ end
+
+ def test_assert_called_on_instance_of_more_than_once
+ assert_called_on_instance_of(Level, :increment, times: 2) do
+ @object.increment
+ @object.increment
+ end
+ end
+
+ def test_assert_called_on_instance_of_with_arguments
+ assert_called_on_instance_of(Level, :<<) do
+ @object << 2
+ end
+ end
+
+ def test_assert_called_on_instance_of_returns
+ assert_called_on_instance_of(Level, :increment, returns: 10) do
+ assert_equal 10, @object.increment
+ end
+
+ assert_equal 1, @object.increment
+ end
+
+ def test_assert_called_on_instance_of_failure
+ error = assert_raises(Minitest::Assertion) do
+ assert_called_on_instance_of(Level, :increment) do
+ # Call nothing...
+ end
+ end
+
+ assert_equal "Expected increment to be called 1 times, but was called 0 times.\nExpected: 1\n Actual: 0", error.message
+ end
+
+ def test_assert_called_on_instance_of_with_message
+ error = assert_raises(Minitest::Assertion) do
+ assert_called_on_instance_of(Level, :increment, "dang it") do
+ # Call nothing...
+ end
+ end
+
+ assert_match(/dang it.\nExpected increment/, error.message)
+ end
+
+ def test_assert_called_on_instance_of_nesting
+ assert_called_on_instance_of(Level, :increment, times: 3) do
+ assert_called_on_instance_of(Level, :decrement, times: 2) do
+ @object.increment
+ @object.decrement
+ @object.increment
+ @object.decrement
+ @object.increment
+ end
+ end
+ end
+
def test_assert_not_called
assert_not_called(@object, :decrement) do
@object.increment
@@ -107,6 +166,30 @@ class MethodCallAssertionsTest < ActiveSupport::TestCase
assert_equal "Expected increment to be called 0 times, but was called 1 times.\nExpected: 0\n Actual: 1", error.message
end
+ def test_assert_not_called_on_instance_of
+ assert_not_called_on_instance_of(Level, :decrement) do
+ @object.increment
+ end
+ end
+
+ def test_assert_not_called_on_instance_of_failure
+ error = assert_raises(Minitest::Assertion) do
+ assert_not_called_on_instance_of(Level, :increment) do
+ @object.increment
+ end
+ end
+
+ assert_equal "Expected increment to be called 0 times, but was called 1 times.\nExpected: 0\n Actual: 1", error.message
+ end
+
+ def test_assert_not_called_on_instance_of_nesting
+ assert_not_called_on_instance_of(Level, :increment) do
+ assert_not_called_on_instance_of(Level, :decrement) do
+ # Call nothing...
+ end
+ end
+ end
+
def test_stub_any_instance
stub_any_instance(Level) do |instance|
assert_equal instance, Level.new