Introduction
Real-world job testing requires handling time, stubbing external services, and verifying negative cases.
Key Concepts
- Time Helpers:
travel_to,freeze_timefor time-dependent tests. - Stubbing: Replacing external calls with controlled responses.
Real World Context
A job calling Stripe needs stubbed API responses. A daily digest needs time-travel tests.
Deep Dive
Stubbing External Services
rubytest "syncs customer to Stripe" do Stripe::Customer.stub(:create, OpenStruct.new(id: "cus_123")) do SyncToStripeJob.perform_now(user.id) end assert_equal "cus_123", user.reload.stripe_customer_id end
Negative Tests
rubytest "no job for deactivated users" do assert_no_enqueued_jobs do OnboardingJob.perform_now(deactivated_user.id) end end
Queue Assertions
rubytest "enqueues to critical queue" do assert_enqueued_with(job: PaymentJob, queue: "critical") do PaymentService.charge(order) end end
Common Pitfalls
- Testing against real external services — Slow, flaky, costly.
- Not testing discard paths — Verify discard_on side effects.
Best Practices
- Stub all external services.
- Test every retry_on and discard_on path.
Summary
- Stub external services for reliable tests.
- Write negative tests for skip conditions.
- Cover every error handling path.
Code Examples
ruby
test "schedules follow-up 3 days later" do
freeze_time do
assert_enqueued_with(job: FollowUpJob, at: 3.days.from_now) do
OnboardingJob.perform_now(user.id)
end
end
end