Skip to content

Testing

Chris Funderburg edited this page Oct 1, 2026 · 2 revisions

How Bòcan is tested, and which command to run. The detail is in DEVELOPMENT.md.

The layers

Layer Where Command Runs in CI
Module unit and integration tests Modules/<Name>/Tests/ make test-<module> Five of the twelve: audio-engine, persistence, metadata, library, ui
App unit tests Tests/AppTests (the BocanTests Xcode target) make test Yes
Snapshot tests The UI package make test-ui No, the snapshot suite is disabled when CI is set
Script tests Scripts/tests make test-scripts Yes, on Linux
End-to-end tests UITests (XCUITest) make test-e2e, make test-e2e-smoke No, opt-in

Which command to run

When Command
During work on one module make test-<module>
Before each commit make format && make lint && make build && make test-coverage
Before a pull request make tests (format, lint, and the full matrix)
Before a release, quick make test-e2e-smoke (about ten minutes)
Before a release, full make test-e2e (about thirty minutes; do not touch the Mac while it runs)

Module tests

Each module is a Swift package with its own tests. The module names for make test-<module> are:

observability, persistence, metadata, library, acoustics, audio-engine, playback, scrobble, subsonic, podcasts, sync-server, ui

make test-audio-engine needs FFmpeg from Homebrew.

Xcode tests and snapshot tests

The BocanTests Xcode target runs in a standalone process with no host app. AppKit rendering is not available there, so the snapshot tests are in the UI package.

Target Command Includes
BocanTests (Xcode) make test View model tests, Observability tests, App source-convention tests
UI package make test-ui View model tests and snapshot tests

Coverage

  • make test-coverage fails if line coverage is below 80%. CI applies the same gate.
  • make coverage-all runs the module tests with coverage and applies a floor for each module.

End-to-end tests

The E2E suite starts the real app many times and drives it through XCUITest. It contains:

  • Journeys through the main user flows
  • Menu crawls and shortcut-parity tests
  • Settings and window crawls
  • Visualizer liveness checks
  • Accessibility identifier audits
  • Loopback servers that stand in for radio stations and podcast feeds, so no test uses the network

The suite is opt-in. It is not part of make test and it does not run on pull requests. The design is in ADR-079 to ADR-086.

Test fixtures

Audio fixtures are checked in. They are never generated when a test runs, so the results do not depend on the encoders on a machine. Each set has a generator script:

Script Produces
Scripts/gen-audio-fixtures.sh Single-file format samples for the tag reader and writer tests
Scripts/gen-library-fixtures.sh A small untagged library tree with edge cases (hidden file, corrupt file, unicode name)
Scripts/gen-picard-fixtures.sh A Picard-tagged library tree with MusicBrainz ids, sort tags, release types, and cover art

Run a script only when you must change a fixture. Delete the affected files first, because the scripts skip files that exist. Then commit the output.

Rules that catch people

  • A new database column needs fixture data. ColumnPopulationGuardTests requires each column of tracks, albums, artists, and cover_art to have a value on at least one fixture row, or an entry in the allow-list with a reason.
  • The in-app help has two guards. The help text is in Modules/UI/Sources/UI/Help/. HelpContentTests fails when a help string has no String Catalog entry. The E2E ShortcutParityTests checks each shortcut the help mentions against the menus. If you change a shortcut, change the help too.
  • Replace fixed sleeps with bounded waits in UI tests.
  • Read the Testing section of GOTCHAS.md before you debug an E2E failure. It lists the known causes of whole-suite failures.

What CI runs

Event Checks
Push to a branch Light CI: lint, format, build, secret scan
Pull request Full suite: build and test, coverage, script tests, Conventional Commit title, release note present

See The Bòcan Release Process for the full flow.

Related pages

Clone this wiki locally