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:
- Source code:
Sources/PalmierPro/(containingModels/Timeline.swift,ViewModel/EditorViewModel.swift, etc.) - Test code:
Tests/PalmierProTests/(organized into subdirectories likeTimeline/,Models/,ClipMath/)
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:
-
Create a file under
Tests/PalmierProTests/<Category>/(e.g.,Tests/PalmierProTests/Models/ClipTests.swift). -
Import the required modules at the top of the file:
import Testing @testable import PalmierPro -
Declare a test suite using a struct with the
@Suiteattribute, providing a descriptive string name. -
Write individual test functions using the
@Testattribute, using#expectfor assertions and#requirefor 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@Suiteand@Testfor structure. - Tests reside in
Tests/PalmierProTests/and gain internal access via@testable import PalmierPro. - Core models in
Sources/PalmierPro/Models/(such asTimeline.swift) are pure structs withCodableconformance, enabling deterministic unit tests. - Use
#expectfor assertions and#requirefor test preconditions. - Run tests with
swift testor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →