Testing Combine publishers

Combine Mid-level Swift 5.5+ iOS 13+ Reviewed By Alok Singh

Pick the fix

How should you test a view model that debounces search input by 300 ms?

Options
Hint 1 of 1

Who controls time in the test?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A Inject a test scheduler, send input, advance time by 300 ms and assert the request

Correct. It's deterministic and instant.

Why not the others?
  • B Send input, call sleep(1), then assert. Slow and flaky on busy CI machines.
  • C Only check that the pipeline compiles. It doesn't test behaviour.
  • D Assert immediately after sending input. The debounced value hasn't been emitted yet.

30-second answer

Subscribe in the test, collect values, and wait for the expected output. In XCTest use an expectation fulfilled in the sink; with Swift Testing or async tests, iterate publisher.values. For timing operators like debounce, inject a scheduler so tests control time instead of sleeping.

Practise saying it · 30 s. No recording, just a timer

Explain how you test Combine code.

Say your answer out loud, then check which of these points you covered:

  • Collect values
  • Expectations or .values
  • Injected schedulers

Deep dive

Make the scheduler a dependency, for example AnySchedulerOf<DispatchQueue>, or a protocol-based one.

Assert the completion as well as the values.

Keep the cancellable alive for the duration of the test.

Use .collect() with a known number of values or completion.

Common mistakes

  • Sleeping in tests to wait for debounce.
  • Letting the subscription deallocate before values arrive.

Senior take & follow-ups

Seniors make time a dependency so tests are fast and deterministic.

Follow-up questions

Think of your answer first, then open the hint.

  1. How do you test debounce without waiting?

    Show hint

    A test scheduler you advance manually.

  2. How do you await a publisher in an async test?

    Show hint

    for await v in publisher.values.

Suggest a fix if something here is wrong or out of date.