Swift testing ftw

download Swift testing ftw

of 35

  • date post

  • Category


  • view

  • download


Embed Size (px)

Transcript of Swift testing ftw

  • Swift Testing FTW!

    Jorge D. Ortiz-Fuentes @jdortiz


  • A Canonical Examples



  • #SwiftTesting


    Basics about unit testing

    4 challenges of Swift Testing

    Proposed enhancements

  • Basics about Unit Testing

  • But my code is always awesome!

  • #SwiftTesting

    Unit TestsProve correctness of different aspects of the

    public interface.

    Prove instead of intuition

    Define contract and assumptions

    Document the code

    Easier refactoring or change

    Reusable code = code + tests

  • #SwiftTesting

    Use Unit Testing Incrementally

    You dont have to write every unit test

    Start with the classes that take care of the logic

    If mixed apply SOLID

    The easier entry point is fixing bugs

  • Time writing tests < Time debugging

  • Ask for your wishes

  • #SwiftTesting

    Types of Unit Tests

    Test return value

    Test state

    Test behavior

  • #SwiftTesting

    The Rules of Testing

    We only test our code

    Only a level of abstraction

    Only public methods

    Only one assertion per test

    Tests are independent of sequence or state

  • 4 Challenges of Swift Testing

  • Lost

  • #SwiftTesting

    New to Swift

    Still learning the language

    Functional Paradigm

    Swift has bugs

  • #SwiftTesting

    Implicitly unwrapped SUT

    SUT cannot be created in init

    Thus, it needs to be optional

    But once set in setUp, it never becomes nil

    Syntax is clearer with an implicitly unwrapped optional.

  • #SwiftTesting


    Works with non custom objects

    But requires objects to be equatable

    Use reference comparison instead

  • #SwiftTesting

    func createSut() { interactor = ShowAllSpeakersInteractorMock() sut = SpeakerListPresenter(interactor: interactor) view = SpeakersListViewMock() sut.view = view } func testViewIsPersisted() { if let persitedView = shut.view as? SpeakersListViewMock { XCTAssertTrue(persistedView === view, Wrong view persisted) } else { XCTFail(View must be persisted) } }

    Example: Test persistence

    public class SpeakersListPresenter { let interactor: ShowAllSpeakersInteractorProtocol public weak var view SpeakersListViewProtocol?

    public init(interactor: ShowAllSpeakersInteractorProtocol) { self.interactor = interaction } }

  • No Courage

  • #SwiftTesting

    Room for improvementBrian Gesiak: XCTest: The Good Parts:

    Replace/customize Testing frameworks



    1,000+ tests

    I add:

    Run tests without the simulator

    Jon Reid provides a method to speed up AppDelegate launch, but not for Swift

  • No Brains

  • #SwiftTesting

    Access control NTFTC It would be nice to have access to internal

    properties, but you should only test the public interface

    Implicit constructors for structs are internal

    However, mocks defined in the same test case can be accessed (internal)

    If not tested, view controllers may not be public. But it makes things more complicated. More on that later.

  • #SwiftTesting

    Create your own templates

    import XCTest import ___PACKAGENAMEASIDENTIFIER___

    class ___FILEBASENAMEASIDENTIFIER___: ___VARIABLE_testSubclass___ { // MARK: - Parameters & Constants // MARK: - Test vatiables. var sut: ___VARIABLE_classUnderTest___! // MARK: - Set up and tear down override func setUp() { super.setUp() createSut() } func createSut() { sut = ___VARIABLE_classUnderTest___() } override func tearDown() { releaseSut() super.tearDown() } func releaseSut() { sut = nil }

  • No Heart

  • #SwiftTesting

    Dependency Injection

    Code of an object depends on other objects.

    Those are considered dependencies.

    Dependencies must be controlled in order to reproduce behavior properly.

  • #SwiftTesting

    Dependency Injection

    Extract and override: move to a method and override in testing class (more fragile)

    Method injection: change the signature of the method to provide the dependency

    Property injection: lazy instantiation

    Constructor injection: not always possible

  • #SwiftTesting

    Stubs & Mocks

    Both are fake objects

    Stubs provide desired responses to the SUT

    Mocks also expect certain behaviors

  • OCMock / OCMockito

    Not Available!

  • #SwiftTesting

    Testing with dependency

    class ViewController: UIViewController {

    @IBOutlet weak var messageLabel: UILabel!

    override func viewDidLoad() { super.viewDidLoad() let userDefaults = NSUserDefaults.standardUserDefaults() let score = userDefaults.integerForKey("PreservedScore") messageLabel.text = String(score) } }

  • #SwiftTesting

    func testMessageLabelDisplaysStoredScore() { var labelMock = LabelMock() sut.messageLabel = labelMock sut.userDefaults = UserDefaultsMock() var view = sut.view if let text = sut.messageLabel.text { XCTAssertEqual(text, "1337", "Label must display the preserved score.") } else { XCTFail("Label text must not be nil.") } } class UserDefaultsMock: NSUserDefaults { override func integerForKey(defaultName: String) -> Int { return 1337 } } class LabelMock: UILabel { var presentedText: String? override internal var text: String? { get { return presentedText } set { presentedText = newValue } } } }

    Dependency injectionimport UIKit

    public class ViewController: UIViewController {

    @IBOutlet public weak var messageLabel: UILabel!

    lazy public var userDefaults = NSUserDefaults.standardUserDefaults()

    override public func viewDidLoad() { super.viewDidLoad() let score = userDefaults.integerForKey("Score") messageLabel.text = String(score) } }

  • Let the Architecture Help You

  • #SwiftTesting

    Clean Architecture

    View (VC) Presenter


    Interactor Repository



  • Follow the Clean Brick Road

  • canonicalexamples.com coupon:


  • Thank you!

  • @jdortiz #CoreDataMT