Support procs for assert_{enqueued,performed}_with

PR #33995 added support for specifying the `args` argument of
`assert_enqueued_with` and `assert_performed_with` as a matcher proc.
In doing so, it added undocumented support for specifying the other
arguments as matcher procs as well.  This commit officially documents
that support, and adds tests to ensure the behavior.
This commit is contained in:
Jonathan Hefner 2020-04-23 19:16:14 -05:00
parent 3f0a35e1e2
commit b16c38ab6a
2 changed files with 63 additions and 82 deletions

View File

@ -351,31 +351,27 @@ module ActiveJob
# assert_enqueued_with(at: Date.tomorrow.noon, queue: "my_queue")
# end
#
# The +at+ and +args+ arguments also accept a proc.
# The given arguments may also be specified as matcher procs that return a
# boolean value indicating whether a job's attribute meets certain criteria.
#
# To the +at+ proc, it will get passed the actual job's at argument.
# For example, a proc can be used to match a range of times:
#
# def test_assert_enqueued_with
# expected_time = ->(at) do
# (Date.yesterday..Date.tomorrow).cover?(at)
# end
# at_matcher = ->(job_at) { (Date.yesterday..Date.tomorrow).cover?(job_at) }
#
# MyJob.set(at: Date.today.noon).perform_later
# assert_enqueued_with(job: MyJob, at: expected_time)
# MyJob.set(wait_until: Date.today.noon).perform_later
#
# assert_enqueued_with(job: MyJob, at: at_matcher)
# end
#
# To the +args+ proc, it will get passed the actual job's arguments
# Your proc needs to return a boolean value determining if
# the job's arguments matches your expectation. This is useful to check only
# for a subset of arguments.
# A proc can also be used to match a subset of a job's args:
#
# def test_assert_enqueued_with
# expected_args = ->(job_args) do
# assert job_args.first.key?(:foo)
# end
# args_matcher = ->(job_args) { job_args[0].key?(:foo) }
#
# MyJob.perform_later(foo: 'bar', other_arg: 'No need to check in the test')
# assert_enqueued_with(job: MyJob, args: expected_args)
# MyJob.perform_later(foo: "bar", other_arg: "No need to check in the test")
#
# assert_enqueued_with(job: MyJob, args: args_matcher)
# end
#
# If a block is passed, asserts that the block will cause the job to be
@ -440,33 +436,31 @@ module ActiveJob
# assert_performed_with(at: Date.tomorrow.noon, queue: "my_queue")
# end
#
# The +at+ and +args+ arguments also accept a proc.
# The given arguments may also be specified as matcher procs that return a
# boolean value indicating whether a job's attribute meets certain criteria.
#
# To the +at+ proc, it will get passed the actual job's at argument.
#
# def test_assert_enqueued_with
# expected_time = ->(at) do
# (Date.yesterday..Date.tomorrow).cover?(at)
# end
#
# MyJob.set(at: Date.today.noon).perform_later
# assert_enqueued_with(job: MyJob, at: expected_time)
# end
#
# To the +args+ proc, it will get passed the actual job's arguments
# Your proc needs to return a boolean value determining if
# the job's arguments matches your expectation. This is useful to check only
# for a subset of arguments.
# For example, a proc can be used to match a range of times:
#
# def test_assert_performed_with
# expected_args = ->(job_args) do
# assert job_args.first.key?(:foo)
# end
# MyJob.perform_later(foo: 'bar', other_arg: 'No need to check in the test')
# at_matcher = ->(job_at) { (Date.yesterday..Date.tomorrow).cover?(job_at) }
#
# MyJob.set(wait_until: Date.today.noon).perform_later
#
# perform_enqueued_jobs
#
# assert_performed_with(job: MyJob, args: expected_args)
# assert_performed_with(job: MyJob, at: at_matcher)
# end
#
# A proc can also be used to match a subset of a job's args:
#
# def test_assert_performed_with
# args_matcher = ->(job_args) { job_args[0].key?(:foo) }
#
# MyJob.perform_later(foo: "bar", other_arg: "No need to check in the test")
#
# perform_enqueued_jobs
#
# assert_performed_with(job: MyJob, args: args_matcher)
# end
#
# If a block is passed, that block performs all of the jobs that were
@ -673,7 +667,7 @@ module ActiveJob
def prepare_args_for_assertion(args)
args.dup.tap do |arguments|
if arguments[:at] && !arguments[:at].respond_to?(:call)
if arguments[:at].acts_like?(:time)
at_range = arguments[:at] - 1..arguments[:at] + 1
arguments[:at] = ->(at) { at_range.cover?(at) }
end

View File

@ -559,25 +559,24 @@ class EnqueuedJobsTest < ActiveJob::TestCase
end
end
def test_assert_enqueued_with_selective_args
args = ->(job_args) do
assert_equal 1, job_args.first[:argument1]
assert job_args.first[:argument2].key?(:b)
end
def test_assert_enqueued_with_supports_matcher_procs
facets = {
job: HelloJob,
args: ["Rails"],
at: Date.tomorrow.noon,
queue: "important",
}
assert_enqueued_with(job: MultipleKwargsJob, args: args) do
MultipleKwargsJob.perform_later(argument2: { b: 2, a: 1 }, argument1: 1)
end
end
facets[:job].set(queue: facets[:queue], wait_until: facets[:at]).perform_later(*facets[:args])
def test_assert_enqueued_with_selective_args_fails
args = ->(job_args) do
false
end
facets.each do |facet, value|
matcher = ->(job_value) { job_value == value }
refuser = ->(job_value) { false }
assert_raise ActiveSupport::TestCase::Assertion do
assert_enqueued_with(job: MultipleKwargsJob, args: args) do
MultipleKwargsJob.perform_later(argument2: { b: 2, a: 1 }, argument1: 1)
assert_enqueued_with(**{ facet => matcher })
assert_raises ActiveSupport::TestCase::Assertion do
assert_enqueued_with(**{ facet => refuser })
end
end
end
@ -1804,18 +1803,6 @@ class PerformedJobsTest < ActiveJob::TestCase
end
end
def test_assert_performed_with_with_at_option_as_a_proc
assert_performed_with(job: HelloJob, at: ->(at) { (4.minutes.from_now..6.minutes.from_now).cover?(at) }) do
HelloJob.set(wait: 5.minutes).perform_later
end
assert_raise ActiveSupport::TestCase::Assertion do
assert_performed_with(job: HelloJob, at: ->(at) { (1.minute.from_now..3.minutes.from_now).cover?(at) }) do
HelloJob.set(wait: 1.minute).perform_later
end
end
end
def test_assert_performed_with_without_block_with_at_option
HelloJob.set(wait_until: Date.tomorrow.noon).perform_later
@ -1838,25 +1825,25 @@ class PerformedJobsTest < ActiveJob::TestCase
end
end
def test_assert_performed_with_selective_args
args = ->(job_args) do
assert_equal 1, job_args.first[:argument1]
assert job_args.first[:argument2].key?(:b)
end
def test_assert_performed_with_supports_matcher_procs
facets = {
job: HelloJob,
args: ["Rails"],
at: Date.tomorrow.noon,
queue: "important",
}
assert_performed_with(job: MultipleKwargsJob, args: args) do
MultipleKwargsJob.perform_later(argument2: { b: 2, a: 1 }, argument1: 1)
end
end
facets[:job].set(queue: facets[:queue], wait_until: facets[:at]).perform_later(*facets[:args])
perform_enqueued_jobs
def test_assert_performed_with_selective_args_fails
args = ->(job_args) do
false
end
facets.each do |facet, value|
matcher = ->(job_value) { job_value == value }
refuser = ->(job_value) { false }
assert_raise ActiveSupport::TestCase::Assertion do
assert_performed_with(job: MultipleKwargsJob, args: args) do
MultipleKwargsJob.perform_later(argument2: { b: 2, a: 1 }, argument1: 1)
assert_performed_with(**{ facet => matcher })
assert_raises ActiveSupport::TestCase::Assertion do
assert_performed_with(**{ facet => refuser })
end
end
end