Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Swiftの “private” を テストする / Testing Swift "private"
Search
Yutaro Muta
February 18, 2025
Technology
0
220
Swiftの “private” を テストする / Testing Swift "private"
Mobile Act OSAKA 15
https://mobileact.connpass.com/event/343364/
Yutaro Muta
February 18, 2025
Tweet
Share
More Decks by Yutaro Muta
See All by Yutaro Muta
猫と暮らす Google Nest Cam生活🐈 / WebRTC with Google Nest Cam
yutailang0119
0
170
Apple Vision Pro購入RTA 1泊3日弾丸ハワイツアー / RTA: Purchase Apple Vision Pro in Hawaii
yutailang0119
0
1.4k
個人開発のたのしみ / Enjoying personal development
yutailang0119
0
1k
バックポートして学ぶ新APIの仕組み
yutailang0119
0
2.8k
Backport AsyncImage
yutailang0119
0
720
xcrun Essentials
yutailang0119
6
1.3k
Let's Coding SwiftUI on iPad!
yutailang0119
1
520
Property Wrapperで遊ぼう / Play with Property Wrapper
yutailang0119
2
320
Back of First Screen AB test of Hatena Bookmark iOS app with Firebase AB Testing
yutailang0119
0
310
Other Decks in Technology
See All in Technology
Copilot coding agentにベットしたいCTOが開発組織で取り組んだこと / GitHub Copilot coding agent in Team
tnir
0
190
An introduction to Claude Code SDK
choplin
2
1k
Deep Security Conference 2025:生成AI時代のセキュリティ監視 /dsc2025-genai-secmon
mizutani
4
2.8k
助けて! XからWaylandに移行しないと新しいGNOMEが使えなくなっちゃう 2025-07-12
nobutomurata
2
200
AWS CDK 入門ガイド これだけは知っておきたいヒント集
anank
5
750
無理しない AI 活用サービス / #jazug
koudaiii
0
100
AIでテストプロセス自動化に挑戦する
sakatakazunori
1
530
PHPからはじめるコンピュータアーキテクチャ / From Scripts to Silicon: A Journey Through the Layers of Computing
tomzoh
2
120
SRE with AI:実践から学ぶ、運用課題解決と未来への展望
yoshiiryo1
0
300
How Do I Contact Jetblue Airlines® Reservation Number: Fast Support Guide
thejetblueairhelpsupport
0
150
SRE不在の開発チームが障害対応と 向き合った100日間 / 100 days dealing with issues without SREs
shin1988
2
2k
20250708オープンエンドな探索と知識発見
sakana_ai
PRO
4
1k
Featured
See All Featured
Fireside Chat
paigeccino
37
3.5k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Designing for humans not robots
tammielis
253
25k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.8k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
18
990
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
60k
Designing for Performance
lara
610
69k
Optimizing for Happiness
mojombo
379
70k
It's Worth the Effort
3n
185
28k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
357
30k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
8
700
Transcript
Swiftの “private” を テストする id:yutailang0119 / @yutailang0119 Mobile Act OSAKA
15 1
Who am I!? • id:yutailang0119 ◦ @yutailang0119 • 株式会社はてな ◦
@京都オフィス ◦ アプリケーションエンジニア ▪ iOS/Android ◦ サービスプラットフォームチーム • try! Swift Tokyo Organizer • AVP座談会 🥽 2
3 Introduction
Introduction • private/fileprivateは、参照範囲を制限 ◦ @testableもアクセスできない ◦ open, package, internalはアクセス可能 •
Javaには @VisibleForTesting がある ◦ https://developer.android.com/reference/androidx/annotation/VisibleForTesting 4
Access Level 5 • open • package • internal •
fileprivate • private https://docs.swift.org/swift-book/documentation/the-swift-programming-language/accesscontrol/
6 Motivation
Motivation • テストのためのinternalを避けたい ◦ e.g.) 🙅 コメントでの規制 VisibleForTesting • アクセスのバイパス手段がほしい
7
8 Proposed solution
9 yutailang0119/swift-bypass-accessing
yutailang0119/swift-bypass-accessing • Swift Macros ◦ @BypassAccess • ___ prefix付きコード生成 PeerMacro
• #if DEBUG & internal 10
PeerMacro @attached(peer, names: prefixed(___), named(___init)) public macro BypassAccess() = #externalMacro(
module: "BypassAccessingMacros", type: "BypassAccessMacro" ) 11
12 Detailed design
Detailed design import BypassAccessing struct Declaration { @BypassAccess private let
property: String = "property" @BypassAccess fileprivate func function() -> String { #function } } 13
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
15 Macro
Macro import BypassAccessing struct Declaration { @BypassAccess private let property:
String = "property" } 16
Expand Macro import BypassAccessing struct Declaration { @BypassAccess private let
property: String = "property" #if DEBUG var ___property: String { property } #endif } 17
Macro import BypassAccessing struct Declaration { @BypassAccess fileprivate func function()
-> String { #function } } 18
Expand Macro import BypassAccessing struct Declaration { @BypassAccess fileprivate func
function() -> String { #function } #if DEBUG func ___function() -> String { function() } #endif } 19
20 Support Grammar
Support Grammar • let • var ◦ Stored ◦ Computed
• func • init 21
Modifier, Accessor • async, @MainActor • throws • static, class
• inout • Generics 22 https://docs.swift.org/swift-book/documentation/the-swift-programming-language/summaryofthegrammar
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 }
Limitation • ❌ privateが現れるインターフェース ◦ Method must be declared private
because its parameter uses a private type • ❌ 型推論を伴うプロパティ ◦ ◦ '@BypassAccess' attribute require TypeAnnotation 24 @BypassAccess private var value = "value"
Support Grammar • 想定利用ケースは、テストを参照 ◦ https://github.com/yutailang0119/swift-bypass-accessing/tree/main/Tests/BypassAccessingTests • 考慮外パターンが存在しそう🫥 25
小噺 • SwiftSyntaxBuilder ◦ 複雑だが、今回のケースでは便利 ▪ 条件に応じて、Expressionを組み合わせ可能 ◦ PlainTextで実装後、SyntaxBuilderで書き直した •
Macroのテストは swift-testing が使えない ◦ XCTest ◦ https://github.com/swiftlang/swift-syntax/issues/2720 26
27 Conclusion
Conclusion • yutailang0119/swift-bypass-accessing ◦ @BypassAccess • 想定外を見つけたら、ご連絡ください📲 28
29 Advertisement
30
try! Swift Tokyo 2025 • 2025/04/09 - 11 • 立川ステージガーデン
• https://tryswift.jp/ 31
hatena.co.jp/recruit 32 32