It wasn’t actually about the result perform_job
returns but that happens when Oban tries to complete the job, at least that’s what I understood from stacktrace.
1) test handle_event/4 schedules the next job in the pipeline after one finishes (MyApp.ObanTelemetryHandlerTest)
apps/my_app/test/my_app/oban_telemetry_handler_test.exs:16
** (ArgumentError) nil given for `id`. comparison with nil is forbidden as it is unsafe. Instead write a query with is_nil/1, for example: is_nil(s.id)
code: Oban.Testing.with_testing_mode(:manual, fn ->
stacktrace:
(ecto 3.8.3) lib/ecto/query/builder/filter.ex:191: Ecto.Query.Builder.Filter.not_nil!/2
(oban 2.12.1) lib/oban/queue/basic_engine.ex:137: Oban.Queue.BasicEngine.complete_job/2
(oban 2.12.1) lib/oban/queue/engine.ex:234: anonymous fn/3 in Oban.Queue.Engine.with_span/4
(telemetry 0.4.3) /Users/system/apps/my-app/deps/telemetry/src/telemetry.erl:272: :telemetry.span/3
(oban 2.12.1) lib/oban/queue/executor.ex:203: Oban.Queue.Executor.ack_event/1
(oban 2.12.1) lib/oban/queue/executor.ex:197: Oban.Queue.Executor.report_finished/1
(oban 2.12.1) lib/oban/queue/executor.ex:80: anonymous fn/1 in Oban.Queue.Executor.call/1
(oban 2.12.1) lib/oban/testing.ex:236: Oban.Testing.perform_job/3
test/my_app/oban_telemetry_handler_test.exs:26: anonymous fn/1 in MyApp.ObanTelemetryHandlerTest."test handle_event/4 schedules the next job in the pipeline after one finishes"/1
(oban 2.12.1) lib/oban/testing.ex:398: Oban.Testing.with_testing_mode/2
test/my_app/oban_telemetry_handler_test.exs:24: (test)
Also when I’ve inspected the actual Oban.Job
that was passed to perform/1
from perform_job
, I see that the id
is nil
.
Not sure that’s because of perform_job
but I do not think so (or maybe
). I mean perform_job
doesn’t actually insert anything as far as I understood by looking at the module.
I’m also using perform_job
in other tests but I’ve never encountered the same error.
Edit
Somehow using perform_job
within with_testing_mode(:manual...
causes some problems
# ...
with_testing_mode(:manual, fn ->
{:ok, result} =
perform_job(Workers.MyWorker, %{
record_id: some_record_id
})
assert_enqueued(
[worker: Workers.SecondWorker, args: %{result_id: result.id}],
1000
)
end)
The above snippet somehow throws the ArgumentError I shared above.
I’ve also tried to use Oban.insert/1
instead of using perform_job/1
hoping that it would insert the job and once my job is handled it would enqueue another one 
# ...
with_testing_mode(:manual, fn ->
%{record_id: some_record_id}
|> Workers.MyWorker.new()
|> Oban.insert()
assert_enqueued(
[worker: Workers.SecondWorker, args: %{result_id: result.id}],
1000
)
end)
but somehow this way my first job didn’t even get processed. At least I didn’t see the IO.inspect
s that I did to ensure it was working the way I assumed it would.
how I could finally make it work was by directly calling perform/1
on my worker 
# ...
with_testing_mode(:manual, fn ->
Workers.MyWorker.perform(%Oban.Job{args: %{record_id: some_record_id}})
assert_enqueued(
[worker: Workers.SecondWorker, args: %{result_id: result.id}],
1000
)
end)
But at that point, is this test useful or necessary? Because I am calling perform/1
directly and I already know that if the job is succesfull the next thing it will do is to schedule another one. Maybe that’s the topic of another question about testing in general.