请写一篇关于【iOS自动化测试:XCTest框架详解】的技术文章

创新之网络
2025-12-18 15:38
阅读 507

被裁后接外包的全栈开发,和老婆异地,周末才能见面。这是我的第17个外包项目,也是我重新找回节奏的关键一战。


去年十月的一个周五晚上,9点42分,我坐在出租屋的电脑前,盯着屏幕上跳动的红色失败用例,手指无意识地敲着机械键盘——咔哒、咔哒、咔哒。窗外是杭州下沙的夜色,楼下烧烤摊还在冒烟,隔壁情侣在吵架,而我,刚被裁员三个月,正为一个iOS外包项目的交付 deadline 焦头烂额。

手机震动了一下,是我老婆发来的消息:“今天又加班?别太拼了,周末见。”
我回了个“嗯”,然后深吸一口气,把脸埋进手掌——我真的快撑不住了

从大厂到自由职业:一场猝不及防的“毕业”

事情得从今年七月说起。我在一家中型互联网公司做了三年全栈开发,月薪15k,房租3500,生活稳定但毫无波澜。直到那个周一晨会,HR把我叫进小会议室,递来一杯咖啡,说:“公司战略调整,你被优化了。”

“优化”这个词,现在听来还是有点讽刺。那天回家路上,我一直在想:房贷怎么办?异地恋怎么维持?她在北京做产品经理,我原计划年底攒够首付就去北京找她团聚。

失业第一个月,我投了67份简历,面了12家公司。有一家问得很直接:“你会iOS自动化测试吗?我们项目要用XCTest做UI回归。”
我支支吾吾答不上来,只说“会写单元测试”。结果可想而知——挂了。

那晚我和老婆视频,她看我脸色不对,问:“是不是面试又没成?”
我点点头,声音有点哑:“感觉自己的技术栈太杂,啥都会一点,但都不精。”
她沉默了几秒,说:“要不……试试接外包?先稳住收入,再补短板?”

于是,我注册了三个外包平台,开始接单。第一个项目是给一个电商App加个Springboot后台接口,报价8000,两周交付。虽然累,但至少银行卡里有了进账。第二个、第三个……慢慢有了口碑,客户开始主动找上门。

直到上个月,一个老客户甩给我一个新需求:“我们有个iOS App要做自动化测试,主要是登录、下单、支付这几个核心路径。你搞过XCTest吗?”

我其实没搞过。但为了拿下这个2.2w的项目,我硬着头皮说:“做过,没问题。”

硬着头皮啃XCTest:从“红条满屏”到“绿灯通行”

接下项目后,我才真正意识到自己踩了多大的坑。

XCTest是Apple官方的测试框架,集成在Xcode里,支持单元测试(Unit Test)和UI测试(UI Test)。听起来简单,但真上手才发现水有多深。

我打开客户的项目代码,发现他们连基本的测试结构都没有。更糟的是,UI全是用Storyboard拖的,没有明确的accessibilityIdentifier——这意味着我连元素都定位不到!

第一周,我的测试用例全是红的
不是“element not found”,就是“timeout waiting for element”。有一次凌晨三点,我对着模拟器里卡死的登录按钮,差点把键盘砸了。

但我知道不能放弃。这项目要是黄了,下个月房租都成问题。而且,这可能是我补齐“移动端测试”能力的关键机会。

于是我开始系统性地补课:

  1. 给所有UI控件加上accessibilityIdentifier
    比如登录按钮:

    loginButton.accessibilityIdentifier = "loginButton"
    

    这样在UI测试里就能用app.buttons["loginButton"]精准定位。

  2. 用XCTestExpectation处理异步操作
    比如网络请求后的页面跳转:

    let expectation = XCTestExpectation(description: "Login success")
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        XCTAssertTrue(app.staticTexts["Home"].exists)
        expectation.fulfill()
    }
    wait(for: [expectation], timeout: 10)
    
  3. 封装公共方法,避免重复代码
    我写了个TestHelper.swift:

    class TestHelper {
        static func login(username: String, password: String, app: XCUIApplication) {
            app.textFields["usernameField"].tap()
            app.textFields["usernameField"].typeText(username)
            app.secureTextFields["passwordField"].tap()
            app.secureTextFields["passwordField"].typeText(password)
            app.buttons["loginButton"].tap()
        }
    }
    
  4. 结合持续集成(CI)跑测试
    客户用的是GitLab CI,我在.gitlab-ci.yml里加了:

    test_ios:
      script:
        - xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 14'
    

三周后,测试覆盖率从0%提升到68%,核心路径全部通过。交付那天,客户发来消息:“兄弟,牛啊!比我们之前外包的团队靠谱多了。”

那一刻,我瘫在椅子上,眼眶有点热。不是因为钱,而是因为——我终于能靠自己的技术吃饭了

面试题挑战:当XCTest遇上Springboot

有意思的是,就在上周,我又去面了一家公司。面试官是个戴黑框眼镜的架构师,开场就扔出一道题:

“假设你有一个Springboot后台,一个iOS前端。如何设计端到端的自动化测试,确保登录功能从API到UI都正常?”

我笑了。这不就是我最近干的事吗?

我答:“我会分三层做:

  1. Springboot层:用JUnit + Mockito测Controller和Service逻辑;
  2. 接口层:用Postman或RestAssured验证API返回;
  3. iOS层:用XCTest做UI测试,模拟真实用户操作。”

我还补充:“关键是数据隔离。比如测试账号要独立,不能污染生产数据。我会在Springboot里加一个@Profile("test")的配置,自动创建测试用户;iOS测试时用这个账号登录。”

面试官点点头:“不错,考虑得很全。”

后来HR打电话来谈薪资,开到了22k。比裁员前高了近50%。我犹豫了一下,还是婉拒了——我现在接外包一个月也能赚这个数,还能自由安排时间,周末飞北京看老婆

异地恋、自由职业与技术人的尊严

很多人问我:“自由职业不稳定,不怕吗?”
怕,当然怕。尤其是半夜改bug、客户催进度、银行余额告急的时候。

但我也越来越清楚:技术人的价值,不在工位上,而在解决问题的能力里

XCTest只是工具,Springboot也只是框架。真正让我翻身的,是那种“死磕到底”的劲儿——就像上周五晚上,我一边调试UI测试,一边和老婆视频:“等这个项目结束,我就能多存点钱,争取明年搬去北京。”

她说:“你现在的状态,比在大厂时好多了。”
我说:“因为我知道,每行代码都在为我们的未来打工。”

给同行的几点建议

如果你也在迷茫,或者正准备入坑iOS自动化测试,分享几点血泪经验:

  1. 别怕从零开始
    XCTest文档其实很友好,Apple的官方示例(比如UI Testing in Xcode)值得反复看。

  2. 测试不是“额外工作”,而是“质量保险”
    客户最怕线上出bug。一套稳定的自动化测试,能让你在交付时底气十足。

  3. 全栈思维很重要
    我之所以能搞定那个“Springboot + iOS”端到端测试,是因为前后端都懂。建议iOS开发者也学点后端,反之亦然。

  4. 保持输出,建立个人品牌
    我现在每周写一篇技术复盘,发在掘金和知乎。不仅帮别人避坑,也让自己思考更系统。

写在最后

凌晨1点,我又一次提交了测试代码。CI流水线跑完,绿色的✓一个个亮起。窗外安静了,烧烤摊收了,情侣也不吵了。

我关掉电脑,给老婆发了条消息:“下周六,我去北京。给你带西湖藕粉。”

然后躺在床上,想起半年前被裁那天的慌乱。
现在回头看,那不是终点,而是我真正掌握自己职业生涯的起点

技术这条路,没有铁饭碗,但有真本事。
只要你愿意动手、愿意学习、愿意在深夜和红条死磕——
你就永远有饭吃,有路走,有爱可守

共勉。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝