| ← Integrations | Home | Next: Pitfalls Reference → |
import HummingbirdTesting
import XCTest
final class UserRouteTests: XCTestCase {
func testCreateUser() async throws {
let app = buildTestApp() // same function as production, with fakes injected
try await app.test(.router) { client in
let response = try await client.execute(
uri: "/users",
method: .post,
headers: [.contentType: "application/json"],
body: ByteBuffer(string: #"{"name":"Alice","email":"alice@example.com"}"#)
)
XCTAssertEqual(response.status, .created)
}
}
}
| Mode | What it tests | When to use |
|---|---|---|
.router |
Routing, middleware, handlers (no network) | All unit/integration tests |
.live |
Real TCP stack, TLS, HTTP/2 | TLS config, WebSocket upgrades |
Use .router for 95%+ of tests. It is orders of magnitude faster than .live and doesn’t consume system ports.
func buildTestApp() throws -> some ApplicationProtocol {
let fakeUserRepo = FakeUserRepository()
await fakeUserRepo.seed([User(id: UUID(), name: "Alice", email: "alice@example.com")])
let dependencies = AppDependencies(
userService: UserService(repository: fakeUserRepo),
emailService: FakeEmailService()
)
let router = Router(context: AppRequestContext.self)
router.add(middleware: DependencyInjectionMiddleware(dependencies: dependencies))
UserController().registerRoutes(on: router.group("/users"))
return Application(router: router)
}
The fake repository is an actor that satisfies the UserRepositoryProtocol in memory. No database. No network. Tests run in milliseconds.
# Stage 1: Build
FROM swift:6.0-jammy AS builder
WORKDIR /app
COPY Package.swift Package.resolved ./
RUN swift package resolve
COPY Sources ./Sources
RUN swift build --configuration release --static-swift-stdlib
# Stage 2: Runtime (no Swift toolchain needed)
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y libcurl4 libxml2 ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN useradd --system --create-home appuser
USER appuser
COPY --from=builder /app/.build/release/MyServer /usr/local/bin/server
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s \
CMD curl -f http://localhost:8080/health || exit 1
ENTRYPOINT ["/usr/local/bin/server"]
Pitfall:
--static-swift-stdlibembeds the Swift runtime into the binary. Without it, your runtime image must useswift:slim(much larger). Always use static linking for production containers.
// Always implement these — required by load balancers, Docker, Kubernetes
router.get("/health") { _, _ in ["status": "ok"] }
router.get("/ready") { _, context in
try await context.dependencies.db.ping()
return ["status": "ok"]
}
swift-aws-lambda-runtime. Hummingbird has an official Lambda transport adapter.JSONDecoder() in hot paths. Use a shared static instance or request.decode(as:context:).| ← Integrations | Home | Next: Pitfalls Reference → |