Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swiftの “private” を テストする / Testing Swift "private"

Yutaro Muta
February 18, 2025

Swiftの “private” を テストする / Testing Swift "private"

Yutaro Muta

February 18, 2025
Tweet

More Decks by Yutaro Muta

Other Decks in Technology

Transcript

  1. Who am I!? • id:yutailang0119 ◦ @yutailang0119 • 株式会社はてな ◦

    @京都オフィス ◦ アプリケーションエンジニア ▪ iOS/Android ◦ サービスプラットフォームチーム • try! Swift Tokyo Organizer • AVP座談会 🥽 2
  2. Introduction • private/fileprivateは、参照範囲を制限 ◦ @testableもアクセスできない ◦ open, package, internalはアクセス可能 •

    Javaには @VisibleForTesting がある ◦ https://developer.android.com/reference/androidx/annotation/VisibleForTesting 4
  3. Access Level 5 • open • package • internal •

    fileprivate • private https://docs.swift.org/swift-book/documentation/the-swift-programming-language/accesscontrol/
  4. Detailed design import BypassAccessing struct Declaration { @BypassAccess private let

    property: String = "property" @BypassAccess fileprivate func function() -> String { #function } } 13
  5. Detailed design import Testing import BypassAccessing @testable import Example struct

    Tests { @Test func test() { let declaration = Declaration() #if DEBUG #expect(declaration.___property == "property") #expect(declaration.___function() == "function()") #endif } } 14
  6. Expand Macro import BypassAccessing struct Declaration { @BypassAccess private let

    property: String = "property" #if DEBUG var ___property: String { property } #endif } 17
  7. Expand Macro import BypassAccessing struct Declaration { @BypassAccess fileprivate func

    function() -> String { #function } #if DEBUG func ___function() -> String { function() } #endif } 19
  8. Modifier, Accessor • async, @MainActor • throws • static, class

    • inout • Generics 22 https://docs.swift.org/swift-book/documentation/the-swift-programming-language/summaryofthegrammar
  9. Modifier, Accessor 23 import BypassAccessing struct Declaration<Element> { @BypassAccess @MainActor

    private init(_ arg: inout String) async throws where Element: Equatable {} #if DEBUG @MainActor static func ___init(_ arg: inout String) async throws -> Self where Element: Equatable { try await Self.init(_: &arg) } #endif }
  10. Limitation • ❌ privateが現れるインターフェース ◦ Method must be declared private

    because its parameter uses a private type • ❌ 型推論を伴うプロパティ ◦   ◦ '@BypassAccess' attribute require TypeAnnotation 24 @BypassAccess private var value = "value"
  11. 30