SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.
SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.
Successfully reported this slideshow.
Activate your 14 day free trial to unlock unlimited reading.
6.
#SwiftTesting
Unit Tests
★ Prove 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
7.
#SwiftTesting
Use Unit Testing
Incrementally
★ You don’t 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
10.
#SwiftTesting
Types of Unit Tests
★ Test return value
★ Test state
★ Test behavior
11.
#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
14.
#SwiftTesting
New to Swift
★ Still learning the language
★ Functional Paradigm
★ Swift has bugs
15.
#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.
16.
#SwiftTesting
XCTAssertEquals
★ Works with non custom objects
★ But requires objects to be equatable
★ Use reference comparison instead
17.
#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:
ShowAllSpeakersInteractorPro
tocol
public weak var view
SpeakersListViewProtocol?
public init(interactor:
ShowAllSpeakersInteractorPro
tocol) {
self.interactor =
interaction
}
}
19.
#SwiftTesting
Room for improvement
★ Brian Gesiak: XCTest: The Good Parts:
• Replace/customize Testing frameworks
• XCTAssertThrows
• assert/precondition
• 1,000+ tests
★ I add:
• Run tests without the simulator
• Jon Reid provides a method to speed up AppDelegate launch,
but not for Swift
21.
#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.
22.
#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
}
24.
#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.
25.
#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
26.
#SwiftTesting
Stubs & Mocks
★ Both are fake objects
★ Stubs provide desired responses to the
SUT
★ Mocks also expect certain behaviors
28.
#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)
}
}
29.
#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 injection
import 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)
}
}