swift-testing — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited swift-testing (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
XCTest is Apple's foundational testing framework. Every test class inherits from XCTestCase and uses setUp/tearDown for lifecycle management.
import XCTest
@testable import MyApp
final class UserServiceTests: XCTestCase {
var sut: UserService!
var mockStore: MockUserStore!
override func setUp() {
super.setUp()
mockStore = MockUserStore()
sut = UserService(store: mockStore)
}
override func tearDown() {
sut = nil
mockStore = nil
super.tearDown()
}
func testFetchUser_withValidID_returnsUser() {
mockStore.stubbedUser = User(id: "1", name: "Alice")
let user = sut.fetchUser(id: "1")
XCTAssertNotNil(user)
XCTAssertEqual(user?.name, "Alice")
}
func testFetchUser_withInvalidID_returnsNil() {
mockStore.stubbedUser = nil
let user = sut.fetchUser(id: "unknown")
XCTAssertNil(user)
}
}The Swift Testing framework replaces XCTest with a more expressive, macro-driven approach. Use @Test for individual tests, #expect for assertions, and @Suite for grouping.
import Testing
@testable import MyApp
@Suite("User Service")
struct UserServiceTests {
let mockStore = MockUserStore()
@Test("fetches user by valid ID")
func fetchValidUser() {
mockStore.stubbedUser = User(id: "1", name: "Alice")
let service = UserService(store: mockStore)
let user = service.fetchUser(id: "1")
#expect(user?.name == "Alice")
}
@Test("returns nil for unknown ID")
func fetchUnknownUser() {
mockStore.stubbedUser = nil
let service = UserService(store: mockStore)
#expect(service.fetchUser(id: "unknown") == nil)
}
}Swift Testing supports parameterized tests natively, eliminating boilerplate for table-driven patterns.
@Test("validates email formats", arguments: [
("[email protected]", true),
("bob@", false),
("", false),
("[email protected]", true),
])
func emailValidation(email: String, isValid: Bool) {
#expect(EmailValidator.isValid(email) == isValid)
}XCTest supports async test methods directly. For callback-based APIs, use XCTestExpectation.
// Direct async/await support
func testFetchProfile_async() async throws {
let service = ProfileService(client: MockHTTPClient())
let profile = try await service.fetchProfile(userID: "1")
XCTAssertEqual(profile.name, "Alice")
}
// Callback-based APIs with expectations
func testFetchProfile_callback() {
let expectation = expectation(description: "Profile fetched")
let service = ProfileService(client: MockHTTPClient())
service.fetchProfile(userID: "1") { result in
switch result {
case .success(let profile):
XCTAssertEqual(profile.name, "Alice")
case .failure(let error):
XCTFail("Unexpected error: \(error)")
}
expectation.fulfill()
}
waitForExpectations(timeout: 5)
}@Test("fetches profile asynchronously")
func fetchProfileAsync() async throws {
let service = ProfileService(client: MockHTTPClient())
let profile = try await service.fetchProfile(userID: "1")
#expect(profile.name == "Alice")
}UI tests use XCUIApplication to interact with the app as a user would. Always prefer accessibility identifiers over text matching for resilient tests.
final class LoginUITests: XCTestCase {
let app = XCUIApplication()
override func setUp() {
super.setUp()
continueAfterFailure = false
app.launchArguments = ["--uitesting"]
app.launch()
}
func testSuccessfulLogin() {
let emailField = app.textFields["login.emailField"]
let passwordField = app.secureTextFields["login.passwordField"]
let loginButton = app.buttons["login.submitButton"]
emailField.tap()
emailField.typeText("[email protected]")
passwordField.tap()
passwordField.typeText("password123")
loginButton.tap()
let welcomeLabel = app.staticTexts["home.welcomeLabel"]
XCTAssertTrue(welcomeLabel.waitForExistence(timeout: 5))
XCTAssertEqual(welcomeLabel.label, "Welcome, Alice")
}
}Set accessibility identifiers in production code:
emailTextField.accessibilityIdentifier = "login.emailField"
passwordTextField.accessibilityIdentifier = "login.passwordField"
submitButton.accessibilityIdentifier = "login.submitButton"Swift's protocol-oriented design makes mocking straightforward. Define dependencies as protocols, then provide mock implementations in tests.
// Production protocol
protocol HTTPClient {
func data(from url: URL) async throws -> (Data, URLResponse)
}
// Production implementation
struct URLSessionHTTPClient: HTTPClient {
let session: URLSession
func data(from url: URL) async throws -> (Data, URLResponse) {
try await session.data(from: url)
}
}
// Test double
final class MockHTTPClient: HTTPClient {
var stubbedData: Data = Data()
var stubbedResponse: URLResponse = HTTPURLResponse()
var capturedURLs: [URL] = []
func data(from url: URL) async throws -> (Data, URLResponse) {
capturedURLs.append(url)
return (stubbedData, stubbedResponse)
}
}Inject dependencies through initializers to make classes testable:
final class ProfileService {
private let client: HTTPClient
init(client: HTTPClient) {
self.client = client
}
func fetchProfile(userID: String) async throws -> Profile {
let url = URL(string: "https://api.example.com/users/\(userID)")!
let (data, _) = try await client.data(from: url)
return try JSONDecoder().decode(Profile.self, from: data)
}
}testFetchUser_withExpiredToken_throwsAuthError is better than testFetch2.@Test and #expect when targeting Swift 5.9+; fall back to XCTest for older targets or UI tests.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.