

At companies like Spotify, ViewModels and Presenters often hold UI-facing business logic, state transitions, and side effects. Interviewers ask this to see whether you can test logic cleanly without depending on the UI framework.
Explain your approach to testing the logic in a ViewModel or Presenter.
Address these points:
Focus on unit-testing strategy rather than UI snapshot or end-to-end testing. A strong answer should cover dependency injection, mocking or faking collaborators, testing input-to-output behavior, handling asynchronous code, and identifying edge cases such as duplicate actions, empty data, and failures.
A ViewModel or Presenter should be tested independently from real services, databases, clocks, and schedulers. Injecting dependencies makes tests deterministic and lets you verify logic without relying on slow or flaky external systems.
presenter = LoginPresenter(auth_service=fake_auth, clock=fake_clock)
These components usually transform inputs into observable state or one-time events. Tests should assert the exact sequence of outputs, such as loading, success, empty, or error, rather than checking implementation details.
assert states == ['loading', 'success']
Async logic often introduces race conditions and flaky tests when real timers or threads are used. Controlled schedulers, fake executors, or synchronous test dispatchers make execution predictable.
scheduler.run_all()
Good tests validate externally visible behavior, not private helper methods or internal data structures. This keeps tests stable when the code is refactored but the contract remains the same.
Robust tests include failure paths, retries, empty results, duplicate user actions, and cancellation. These cases often reveal bugs in state management more than the happy path does.
presenter.on_submit()
presenter.on_submit() # verify duplicate submit is ignored