View Source Testing Queues
Where workers are the primary "unit" of an Oban system, queues are the
"integration" point between the database and your application. That means to
test queues and the jobs within them, your tests will have to interact with the
database. To simplify that interaction, reduce boilerplate, and make assertions
more expressive Oban.Testing
provides a variety of helpers.
Asserting Enqueued Jobs
During test runs you don't typically want to execute jobs. Rather, you need
to verify that the job was enqueued properly. With the recommended test setup
queues and plugins are disabled, and jobs won't be inserted into the database at all.
Instead, they'll be executed immediately within the calling process.
The Oban.Testing.assert_enqueued/2
and Oban.Testing.refute_enqueued/2
helpers
simplify running queries to check for those available
or scheduled
jobs
sitting in the database.
Let's look at an example where we want to check that an activation job is enqueued after a user signs up:
test "scheduling activation upon sign up" do
{:ok, account} = MyApp.Account.sign_up(email: "parker@example.com")
assert_enqueued worker: MyApp.ActivationWorker, args: %{id: account.id}, queue: :default
end
Likewise, we can also refute that a job was enqueued. The refute_enqueued
helper takes the same arguments as assert_enqueued
, though you should take
care to be as unspecific as possible.
Building on the example above, let's refute that a job is enqueued when account sign up fails:
test "bypassing activation when sign up fails" do
{:error, _reason} = MyApp.Account.sign_up(email: "parker@example.com")
refute_enqueued worker: MyApp.ActivationWorker
end
Asserting Multiple Jobs
Asserting and refuting about a single job isn't always enough. Sometimes you
need to check for multiple jobs at once, or perform more complex assertions on
the jobs themselves. In that situation, you can use all_enqueued
instead.
The first example we'll look at asserts that multiple jobs from the same worker are enqueued all at once:
test "enqueuing one job for each child record" do
:ok = MyApp.Account.notify_owners(account())
assert jobs = all_enqueued(worker: MyApp.NotificationWorker)
assert 3 == length(jobs)
end
The enqueued
helpers all build dynamic queries to check for jobs within the
database. Dynamic queries don't work for complex objects with nested values or a
partial set of keys. In that case, you can use all_enqueued
to pull jobs into
your tests and use the full power of pattern matching for assertions.
test "enqueued jobs have args that match a particular pattern" do
:ok = MyApp.Account.notify_owners(account())
for job <- all_enqueued(queue: :default) do
assert %{"email" => _, "avatar" => %{"url" => _}} = job.args
end
end
Integration Testing Queues
During integration tests it may be necessary to run jobs because they do work
essential for the test to complete, i.e. sending an email, processing media,
etc. You can execute all available jobs in a particular queue by calling
Oban.drain_queue/1,2
directly from your tests.
For example, to process all pending jobs in the "mailer" queue while testing some business logic:
defmodule MyApp.BusinessTest do
use MyApp.DataCase, async: true
alias MyApp.{Business, Worker}
test "we stay in the business of doing business" do
:ok = Business.schedule_a_meeting(%{email: "monty@brewster.com"})
assert %{success: 1, failure: 0} = Oban.drain_queue(queue: :mailer)
# Now, make an assertion about the email delivery
end
end
See Oban.drain_queue/1,2
for a myriad of options and additional details.