How to mock UNNotificationResponse in unit tests

Issue #708 The best way to test is to not have to mock at all. The second best way is to have your own abstraction over the things you would like to test, either it is in form of protocol or some function injection. But in case you want a quick way to test things, and want to test as real as possible, then for some cases we can be creative to mock the real objects....

December 7, 2020 路 3 min 路 Khoa Pham

How to avoid multiple match elements in UITests from iOS 13

Issue #691 Supposed we want to present a ViewController, and there exist both UIToolbar in both the presenting and presented view controllers. From iOS 13, the model style is not full screen and interactive. From UITests perspective there are 2 UIToolbar, we need to specify the correct one to avoid multiple match errors let editButton = app.toolbars["EditArticle.Toolbar"].buttons["Edit"] Updated at 2020-11-04 10:02:29

November 4, 2020 路 1 min 路 Khoa Pham

How to use accessibility container in UITests

Issue #690 Use accessibilityElements to specify containment for contentView and buttons. You can use Accessibility Inspector from Xcode to verify. class ArticleCell: UICollectionViewCell { let authorLabel: UILabel let dateLabel: UILabel let viewLabel: UILabel let deleteButton: UIButton private func setupAccessibility() { contentView.isAccessibilityElement = true contentView.accessibilityLabel = "This article is written by Nobita on Dec 4th 2020" viewLabel.isAccessibilityElement = true // Default is false viewLabel.accessibilityTraits.insert(.button) // Treat UILabel as button to VoiceOver accessibilityElements = [contentView, viewLabel, deleteButton] isAccessibilityElement = false } } This works OK under Voice Over and Accessibility Inspector....

November 4, 2020 路 1 min 路 Khoa Pham

How to test DispatchQueue in Swift

Issue #646 Sync the DispatchQueue Pass DispatchQueue and call queue.sync to sync all async works before asserting Use mock Use DispatchQueueType and in mock, call the work immediately import Foundation public protocol DispatchQueueType { func async(execute work: @escaping @convention(block) () -> Void) } extension DispatchQueue: DispatchQueueType { public func async(execute work: @escaping @convention(block) () -> Void) { async(group: nil, qos: .unspecified, flags: [], execute: work) } } final class MockDispatchQueue: DispatchQueueType { func async(execute work: @escaping @convention(block) () -> Void) { work() } }

April 29, 2020 路 1 min 路 Khoa Pham

How to assert asynchronously in XCTest

Issue #644 import XCTest extension XCTestCase { /// Asynchronously assertion func XCTAssertWait( timeout: TimeInterval = 1, _ expression: @escaping () -> Void, _: String = "", file _: StaticString = #file, line _: UInt = #line ) { let expectation = self.expectation(description: #function) DispatchQueue.main.asyncAfter(deadline: .now() + timeout) { expression() expectation.fulfill() } let waiter = XCTWaiter() XCTAssertTrue(waiter.wait(for: [expectation], timeout: timeout + 1) == .completed) } } Updated at 2020-04-28 09:23:59

April 28, 2020 路 1 min 路 Khoa Pham

How to iterate over XCUIElementQuery in UITests

Issue #628 extension XCUIElementQuery: Sequence { public typealias Iterator = AnyIterator<XCUIElement> public func makeIterator() -> Iterator { var index = UInt(0) return AnyIterator { guard index < self.count else { return nil } let element = self.element(boundBy: Int(index)) index = index + 1 return element } } } extension NSPredicate { static func label(contains string: String) -> NSPredicate { NSPredicate(format: "label CONTAINS %@", string) } } let books = app.collectionViews.cells.matching( NSPredicate....

March 20, 2020 路 1 min 路 Khoa Pham

How to test drag and drop in UITests

Issue #583 In UITests, we can use press from XCUIElement to test drag and drop let fromCat = app.buttons["cat1"].firstMatch let toCat = app.buttons["cat2"] let fromCoordinate = fromCat.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)) let toCoordinate = toCat.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: -0.5)) 1, thenDragTo: toCoordinate) and then take screenshot let screenshot = XCUIScreen.main.screenshot() let attachment = XCTAttachment(screenshot: screenshot) attachment.lifetime = .keepAlways = name add(attachment) Screenshot capturing happens after the action, so it may be too late....

January 23, 2020 路 1 min 路 Khoa Pham

How to generate XCTest test methods

Issue #576 Code See Spek Override testInvocations to specify test methods Returns an array of invocations representing each test method in the test case. Because testInvocations is unavailable in Swift, we need to use ObjC #import "include/SpekHelperTestCase.h" @implementation SpekHelperTestCase - (instancetype)init { self = [super initWithInvocation: nil]; return self; } + (NSArray<NSInvocation *> *)testInvocations { NSArray<NSString *> *selectorStrings = [self spekGenerateTestMethodNames]; NSMutableArray<NSInvocation *> *invocations = [NSMutableArray arrayWithCapacity:selectorStrings....

January 12, 2020 路 2 min 路 Khoa Pham

How to use passed launch arguments in UITests

Issue #537 Specify launch arguments In xcodebuild, specify launch arguments. You can specify this under Launch Arguments in Run action of the app scheme or UITest scheme -AppleLanguages (jp) -AppleLocale (jp_JP) (lldb) po ProcessInfo().arguments 鈻 11 elements - 0 : "/Users/khoa/Library/Developer/CoreSimulator/Devices/561F2B45-26B2-4897-98C4-8A917AEB48D2/data/Containers/Bundle/Application/436E0A43-8323-4F53-BBE0-6F75F674916F/" - 1 : "-AppleLanguages" - 2 : "(ja)" - 3 : "-AppleTextDirection" - 4 : "NO" - 5 : "-AppleLocale" - 6 : "ja_JP" - 7 : "-NSTreatUnknownArgumentsAsOpen" - 8 : "NO" - 9 : "-ApplePersistenceIgnoreState" - 10 : "YES" In UITests, pass launch arguments from UITest scheme to UITest application...

December 10, 2019 路 1 min 路 Khoa Pham

How to add monkey test to iOS apps

Issue #484 Use SwiftMonkey which adds random UITests gestures Add to UITests target target 'MyAppUITests' do pod 'R.swift', '~> 5.0' pod 'SwiftMonkey', '~> 2.1.0' end Troubleshooting Failed to determine hittability of Button Failed to determine hittability of Button: Unable to fetch parameterized attribute XC_kAXXCParameterizedAttributeConvertHostedViewPositionFromContext, remote interface does not have this capability. This happens when using SwiftMonkey and somewhere in our code uses isHittable, so best to avoid that by having isolated monkey test only...

November 1, 2019 路 1 min 路 Khoa Pham

How to configure test target in Xcode

Issue #478 This applies to Main targets App Framework Test targets Unit tests UI tests Examples Dependencies used Main target: Sugar Test target: Nimble, Quick Examples Cocoapods Carthage Notes Make sure test target can link to all the frameworks it needs. This includes frameworks that Test targets use, and possibly frameworks that Main target uses ! Remember to 鈥淐lean Build Folder鈥 and 鈥淐lear Derived Data鈥 so that you鈥檙e sure it works....

October 29, 2019 路 2 min 路 Khoa Pham

How to test Date with timezone aware in Swift

Issue #402 I want to test if a date has passed another date let base = Date(timeIntervalSince1970: 1567756697) XCTAssertEqual(validator.hasPassed(event: event, date: base), true) My hasPassed is using Calendar.current func minuteSinceMidnight(date: Date) -> MinuteSinceMidnight { let calendar = Calendar.current let start = calendar.startOfDay(for: date) return Int(date.timeIntervalSince(start)) / 60 } But the minute is always having timezone applied. Even if I try with DateComponents func minuteSinceMidnight(date: Date) -> MinuteSinceMidnight { let components = calendar....

September 6, 2019 路 2 min 路 Khoa Pham

How to organise test files

Issue #327 In terms of tests, we usually have files for unit test, UI test, integeration test and mock. Out of sight, out of mind. Unit tests are for checking specific functions and classes, it鈥檚 more convenient to browse them side by side with source file. For example in Javascript, Kotlin and Swift index.js index.test.js index.mock.js LocationManager.kt LocationManager.mock.kt LocationManager.test.kt BasketHandler.swift BasketHandler.mock.swift BasketHandler.test.swift Integration tests check features or sub features, and may cover many source files, it鈥檚 better to place them in feature folders...

June 25, 2019 路 1 min 路 Khoa Pham

How to test LaunchScreen in iOS

Issue #249 Making splash screen with LaunchScreen.storyboard is now the default way to do in iOS. Testing it with UITests is a bit tricky as this screen is showed the system, and if we test that, we are just testing the system. What we should test is the content we put in the LaunchScreen storyboard. Is it showing correctly on different screen sizes? Is it missing any texts or images?...

May 21, 2019 路 1 min 路 Khoa Pham

How to deal with animation in UITests in iOS

Issue #143 Today I was writing tests and get this error related to app idle t = 23.06s Assertion Failure: <unknown>:0: Failed to scroll to visible (by AX action) Button, 0x6000003827d0, traits: 8858370049, label: 'cart', error: Error -25204 performing AXAction 2003 on element <XCAccessibilityElement: 0x7fc391a2bd60> pid: 91461, elementOrHash.elementID: 140658975676048.128 It turns out that the project uses a HUD that is performing some progress animation. Even it was being called HUD....

January 8, 2018 路 1 min 路 Khoa Pham

How to use Given When Then in Swift tests

Issue #73 Spec Using spec testing framework like Quick is nice, which enables BDD style. describe("the 'Documentation' directory") { it("has everything you need to get started") { let sections = Directory("Documentation").sections expect(sections).to(contain("Organized Tests with Quick Examples and Example Groups")) expect(sections).to(contain("Installing Quick")) } context("if it doesn't have what you're looking for") { it("needs to be updated") { let you = You(awesome: true) expect{you.submittedAnIssue}.toEventually(beTruthy()) } } } But in case you don鈥檛 want additional frameworks, and want to live closer to Apple SDKs as much as possible, here are few tips....

September 13, 2017 路 2 min 路 Khoa Pham

How to run UI Test with system alert in iOS

Issue #48 Continue my post When you work with features, like map view, you mostly need permissions, and in UITests you need to test for system alerts. Add interruption monitor This is the code. Note that you need to call app.tap() to interact with the app again, in order for interruption monitor to work addUIInterruptionMonitor(withDescription: "Location permission", handler: { alert in alert.buttons["Allow"].tap() return true }) app.tap() Note that you don鈥檛 always need to handle the returned value of addUIInterruptionMonitor...

June 2, 2017 路 2 min 路 Khoa Pham