11. - Defines module = YES -> classes in app exported as module
- “Product module name” is the name of what you import in test file
12. // BananaViewController.swift
public class BananaViewController: UIViewController {
// ...
}
- To test classes, they must be exported in module, so they must be public
- This goes for all classes, not just view controllers
13. // BananaViewControllerTests.swift
import BananaApp
import XCTest
class BananaViewControllerTests: XCTestCase {
var viewController: BananaViewController!
// ...
}
- We import our defined module
- Since class is public, we can reference it from imported module
14. // BananaViewControllerTests.swift
import BananaApp
import XCTest
class BananaViewControllerTests: XCTestCase {
var viewController: BananaViewController!
// ...
}
- We import our defined module
- Since class is public, we can reference it from imported module
15. // BananaViewControllerTests.swift
import BananaApp
import XCTest
class BananaViewControllerTests: XCTestCase {
var viewController: BananaViewController!
// ...
}
- We import our defined module
- Since class is public, we can reference it from imported module
17. // BananaViewController.swift
import UIKit
public class BananaViewController: UIViewController {
// ...
public override func viewDidLoad() {
super.viewDidLoad()
updateButtons()
}
private func updateButtons() {
moreButton.enabled = bananaCount < 10
lessButton.enabled = bananaCount > 0
}
}
- BananaViewController overrides viewDidLoad to update its buttons
- Let’s test this behavior
18. // BananaViewController.swift
import UIKit
public class BananaViewController: UIViewController {
// ...
public override func viewDidLoad() {
super.viewDidLoad()
updateButtons()
}
private func updateButtons() {
moreButton.enabled = bananaCount < 10
lessButton.enabled = bananaCount > 0
}
}
- BananaViewController overrides viewDidLoad to update its buttons
- Let’s test this behavior
19. // BananaViewController.swift
import UIKit
public class BananaViewController: UIViewController {
// ...
public override func viewDidLoad() {
super.viewDidLoad()
updateButtons()
}
private func updateButtons() {
moreButton.enabled = bananaCount < 10
lessButton.enabled = bananaCount > 0
}
}
- BananaViewController overrides viewDidLoad to update its buttons
- Let’s test this behavior
20. // BananaViewController.swift
import UIKit
public class BananaViewController: UIViewController {
// ...
public override func viewDidLoad() {
super.viewDidLoad()
updateButtons()
}
private func updateButtons() {
moreButton.enabled = bananaCount < 10
lessButton.enabled = bananaCount > 0
}
}
- BananaViewController overrides viewDidLoad to update its buttons
- Let’s test this behavior
21. // BananaViewControllerTests.swift
class BananaViewControllerTests: XCTestCase {
var viewController: BananaViewController!
override func setUp() {
viewController = BananaViewController()
let _ = viewController.view
}
func testLessButtonIsDisabled() {
XCTAssertFalse(viewController.lessButton.enabled)
}
}
- Here we test the less button is disabled
- But when we run the tests, they fail
- Need to access view to trigger viewDidLoad
22. // BananaViewControllerTests.swift
class BananaViewControllerTests: XCTestCase {
var viewController: BananaViewController!
override func setUp() {
viewController = BananaViewController()
let _ = viewController.view
}
func testLessButtonIsDisabled() {
XCTAssertFalse(viewController.lessButton.enabled)
}
}
- Here we test the less button is disabled
- But when we run the tests, they fail
- Need to access view to trigger viewDidLoad
23. // BananaViewControllerTests.swift
class BananaViewControllerTests: XCTestCase {
var viewController: BananaViewController!
override func setUp() {
viewController = BananaViewController()
let _ = viewController.view
}
func testLessButtonIsDisabled() {
XCTAssertFalse(viewController.lessButton.enabled)
}
}
- Here we test the less button is disabled
- But when we run the tests, they fail
- Need to access view to trigger viewDidLoad
24. // BananaViewControllerTests.swift
class BananaViewControllerTests: XCTestCase {
var viewController: BananaViewController!
override func setUp() {
viewController = BananaViewController()
let _ = viewController.view
}
func testLessButtonIsDisabled() {
XCTAssertFalse(viewController.lessButton.enabled)
}
}
XCTAssertFalse failed
- Here we test the less button is disabled
- But when we run the tests, they fail
- Need to access view to trigger viewDidLoad
25. // BananaViewControllerTests.swift
class BananaViewControllerTests: XCTestCase {
var viewController: BananaViewController!
override func setUp() {
viewController = BananaViewController()
let _ = viewController.view
}
func testLessButtonIsDisabled() {
XCTAssertFalse(viewController.lessButton.enabled)
}
}
- Here we test the less button is disabled
- But when we run the tests, they fail
- Need to access view to trigger viewDidLoad
28. // BananaViewControllerTests.swift
let storyboard = UIStoryboard(name: "Main", bundle: nil)
viewController =
storyboard.instantiateViewControllerWithIdentifier(
"BananaViewControllerID") as BananaViewController
- You can instantiate any view controller with an ID in your tests
- If it’s the initial view controller in your storyboard, you don’t need an identifier
29. // BananaViewControllerTests.swift
let storyboard = UIStoryboard(name: "Main", bundle: nil)
viewController =
storyboard.instantiateViewControllerWithIdentifier(
"BananaViewControllerID") as BananaViewController
viewController =
storyboard.instantiateInitialViewController()
as BananaViewController
- You can instantiate any view controller with an ID in your tests
- If it’s the initial view controller in your storyboard, you don’t need an identifier
30. public class BananaViewController: UIViewController {
@IBOutlet public weak var countLabel: UILabel!
@IBOutlet public weak var moreButton: UIButton!
@IBOutlet public weak var lessButton: UIButton!
// ...
}
- And remember, XIB and storyboard files set IBOutlet properties during -viewDidLoad
31. // BananaViewControllerTests.swift
let storyboard = UIStoryboard(name: "Main", bundle: nil)
viewController =
storyboard.instantiateViewControllerWithIdentifier(
"BananaViewControllerID") as BananaViewController
let _ = viewController.view
XCTAssertFalse(viewController.lessButton.enabled)
- So if you access an IBOutlet prior to triggering -viewDidLoad, you’ll hit an assert
32. Thread 1: EXC_BAD_INSTRUCTION
// BananaViewControllerTests.swift
let storyboard = UIStoryboard(name: "Main", bundle: nil)
viewController =
storyboard.instantiateViewControllerWithIdentifier(
"BananaViewControllerID") as BananaViewController
let _ = viewController.view
XCTAssertFalse(viewController.lessButton.enabled)
- So if you access an IBOutlet prior to triggering -viewDidLoad, you’ll hit an assert
33. // BananaViewControllerTests.swift
let storyboard = UIStoryboard(name: "Main", bundle: nil)
viewController =
storyboard.instantiateViewControllerWithIdentifier(
"BananaViewControllerID") as BananaViewController
let _ = viewController.view
XCTAssertFalse(viewController.lessButton.enabled)
- So if you access an IBOutlet prior to triggering -viewDidLoad, you’ll hit an assert