How to Write Unit Tests for the Palmier Pro Backend

Unit tests in Palmier Pro are written in Swift using Apple's modern Testing framework, importing the backend module with @testable import PalmierPro, and organized into suites using the @Suite and @Test macros with #expect assertions.

The Palmier Pro backend, housed in the palmier-io/palmier-pro repository, provides a pure Swift foundation for video editing logic under Sources/PalmierPro. Writing unit tests for this backend involves leveraging the Testing framework—Apple’s successor to XCTest—to validate immutable model structures and deterministic business logic without UI dependencies. This guide covers the exact file structure, import patterns, and assertion patterns used throughout the codebase.

Testing Architecture and Framework Setup

The Testing Framework

Palmier Pro adopts Apple’s Testing framework instead of the older XCTest. This DSL provides a declarative, Swift-native syntax where tests are functions marked with @Test and grouped into structs annotated with @Suite.

In Tests/PalmierProTests/Timeline/TimelineRangeSelectionTests.swift, the pattern looks like this:

import Testing
@testable import PalmierPro

@Suite("Timeline range selection")
struct TimelineRangeSelectionTests {
    @Test func normalizationReversesInvertedRanges() {
        let selection = TimelineRangeSelection(start: 100, end: 50)
        #expect(selection.normalized.start == 50)
        #expect(selection.normalized.end == 100)
    }
}

The #expect macro evaluates boolean expressions and records failures without crashing the test runner. Unlike XCTest, you do not inherit from XCTestCase or use XCTAssert functions.

Test Target Configuration

The test target is defined in Package.swift alongside the main library. The directory structure follows Swift Package Manager conventions:

The @testable attribute in import PalmierPro grants access to internal methods and initializers, allowing you to test implementation details without exposing them as public API.

Writing Your First Unit Test

Follow these steps to add a new unit test to the Palmier Pro backend:

  1. Create a file under Tests/PalmierProTests/<Category>/ (e.g., Tests/PalmierProTests/Models/ClipTests.swift).

  2. Import the required modules at the top of the file:

    import Testing
    @testable import PalmierPro
  3. Declare a test suite using a struct with the @Suite attribute, providing a descriptive string name.

  4. Write individual test functions using the @Test attribute, using #expect for assertions and #require for preconditions that must succeed.

A minimal test file structure looks like this:

import Testing
@testable import PalmierPro

@Suite("Clip manipulation")
struct ClipManipulationTests {
    @Test func durationClampingDropsOutOfBoundsKeyframes() {
        // Arrange
        var clip = Clip(
            mediaRef: "sample.mov",
            startFrame: 0,
            durationFrames: 100,
            trimStartFrame: 0,
            trimEndFrame: 0,
            speed: 1.0,
            volume: 1.0,
            fadeInFrames: 0,
            fadeOutFrames: 0,
            fadeInInterpolation: .linear,
            fadeOutInterpolation: .linear,
            opacity: 1.0,
            transform: Transform(),
            crop: Crop(),
            linkGroupId: nil,
            captionGroupId: nil,
            textContent: nil,
            textStyle: nil,
            opacityTrack: nil,
            positionTrack: nil,
            scaleTrack: nil,
            rotationTrack: nil,
            cropTrack: nil,
            volumeTrack: KeyframeTrack<Double>(keyframes: [
                .init(frame: 80, value: -6),
                .init(frame: 120, value: -3)
            ])
        )
        
        // Act
        clip.setDuration(60)
        
        // Assert
        #expect(clip.durationFrames == 60)
        #expect(clip.volumeTrack?.keyframes.count == 1)
        #expect(clip.volumeTrack?.keyframes.first?.frame == 80)
    }
}

Testing Core Models and Business Logic

Validating Model Serialization

Because core models like Timeline, Clip, and Track conform to Codable, tests should verify round-trip serialization. Encode a model to JSON, decode it back, and assert equality:

@Test func clipSerializationRoundTrip() throws {
    let original = Clip(mediaRef: "test.mov", startFrame: 0, durationFrames: 30)
    let encoded = try JSONEncoder().encode(original)
    let decoded = try JSONDecoder().decode(Clip.self, from: encoded)
    #expect(original == decoded)
}

Boundary Validation

Test that methods correctly clamp values to valid ranges. For example, when calling clip.setFade(.left, frames: -5), the implementation should store fadeInFrames as 0 rather than crashing or accepting invalid input.

Keyframe Sampling

The KeyframeTrack type provides deterministic interpolation. Create tracks with known values and assert that sample(at:) returns the expected interpolated result:

@Test func linearKeyframeInterpolation() {
    let track = KeyframeTrack<Double>(keyframes: [
        .init(frame: 0, value: 0.0),
        .init(frame: 100, value: 1.0)
    ])
    #expect(track.sample(at: 50) == 0.5)
}

Running Tests Locally and in CI

Execute the full test suite from the repository root using the Swift Package Manager:

swift test

Alternatively, open the project in Xcode and press ⌘U (or select Product → Test). The Testing framework integrates with Xcode’s Test Navigator, displaying @Suite and @Test declarations hierarchically.

The CI pipeline configured in GitHub Actions runs swift test on every push, ensuring that pure logic in Sources/PalmierPro remains regression-free across macOS versions.

Summary

  • Palmier Pro uses Apple’s Testing framework (import Testing) rather than XCTest, utilizing @Suite and @Test for structure.
  • Tests reside in Tests/PalmierProTests/ and gain internal access via @testable import PalmierPro.
  • Core models in Sources/PalmierPro/Models/ (such as Timeline.swift) are pure structs with Codable conformance, enabling deterministic unit tests.
  • Use #expect for assertions and #require for test preconditions.
  • Run tests with swift test or Xcode’s Test action; the same command executes in CI pipelines.

Frequently Asked Questions

Does Palmier Pro use XCTest or the new Testing framework?

Palmier Pro uses Apple’s modern Testing framework (introduced as a successor to XCTest). You will see import Testing rather than import XCTest, and tests use @Test functions instead of XCTestCase subclasses.

How do I access internal methods and initializers in my unit tests?

Use @testable import PalmierPro at the top of your test file. This attribute exposes internal access-level members to the test target, allowing you to validate construction logic and helper methods without making them public.

Where should I place new test files in the repository?

Create new Swift files under Tests/PalmierProTests/, organizing them into subdirectories that mirror the source structure (e.g., Tests/PalmierProTests/Models/ for tests covering Sources/PalmierPro/Models/).

Can I run Palmier Pro backend tests without opening Xcode?

Yes. Since the project is a Swift Package Manager project defined by Package.swift, you can run the entire test suite from the command line with swift test. This works on any macOS host with the Swift toolchain installed, making it ideal for CI/CD pipelines.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →