Skip to content

Instantly share code, notes, and snippets.

@eofster
Created November 17, 2015 13:40
Show Gist options
  • Save eofster/e988ac34d4b4670d576f to your computer and use it in GitHub Desktop.
Save eofster/e988ac34d4b4670d576f to your computer and use it in GitHub Desktop.
Dependency injection example with tests
import Foundation
import XCTest
//////////////////////////////////////////////////////////////////////
// Preferences
protocol UserDefaults {
func stringForKey(key: String) -> String
}
class Preferences {
let userDefaults: UserDefaults
init(userDefaults: UserDefaults) {
self.userDefaults = userDefaults
}
var username: String {
return userDefaults.stringForKey("Username")
}
}
class PreferencesTests: XCTestCase {
func testGetsUsernameFromUserDefaults() {
let userDefaultsSpy = UserDefaultsSpy()
userDefaultsSpy.stringForKeyResult = "john"
let preferences = Preferences(userDefaults: userDefaultsSpy)
let username = preferences.username
XCTAssertTrue(userDefaultsSpy.didCallStringForKey)
XCTAssertEqual(userDefaultsSpy.keyPassedToStringForKey, "Username")
XCTAssertEqual(username, "john")
}
}
//////////////////////////////////////////////////////////////////////
// Preferences logger
protocol LogOutput {
func logMessage(message: String)
}
class PreferencesLogger {
let preferences: Preferences
let output: LogOutput
init(preferences: Preferences, output: LogOutput) {
self.preferences = preferences
self.output = output
}
func log() {
output.logMessage("Username: \(preferences.username)")
}
}
class PreferencesLoggerTests: XCTestCase {
func testLogsUsername() {
let userDefaultsStub = UserDefaultsSpy()
userDefaultsStub.stringForKeyResult = "john"
let preferences = Preferences(userDefaults: userDefaultsStub)
let logOutputSpy = LogOutputSpy()
let preferencesLogger = PreferencesLogger(preferences: preferences, output: logOutputSpy)
preferencesLogger.log()
XCTAssertEqual(logOutputSpy.loggedMessage, "Username: john")
}
}
//////////////////////////////////////////////////////////////////////
// Test doubles
class UserDefaultsSpy: UserDefaults {
var stringForKeyResult = ""
private(set) var didCallStringForKey = false
private(set) var keyPassedToStringForKey = ""
func stringForKey(key: String) -> String {
didCallStringForKey = true
keyPassedToStringForKey = key
return stringForKeyResult
}
}
class LogOutputSpy: LogOutput {
private(set) var loggedMessage = ""
func logMessage(message: String) {
loggedMessage = message
}
}
//////////////////////////////////////////////////////////////////////
// UserDefaults implementation
class SystemUserDefaultsAdapter: UserDefaults {
let systemUserDefaults: NSUserDefaults
init(systemUserDefaults: NSUserDefaults) {
self.systemUserDefaults = systemUserDefaults
}
func stringForKey(key: String) -> String {
if let string = systemUserDefaults.stringForKey(key) {
return string
} else {
fatalError("Could not find string for key: \(key)")
}
}
}
// LogOutput implementation
class SystemConsoleOutput: LogOutput {
func logMessage(message: String) {
print(message)
}
}
//////////////////////////////////////////////////////////////////////
// Usage
NSUserDefaults.standardUserDefaults().setObject("john", forKey: "Username")
let userDefaults = SystemUserDefaultsAdapter(systemUserDefaults: NSUserDefaults.standardUserDefaults())
let preferences = Preferences(userDefaults: userDefaults)
let preferencesLogger = PreferencesLogger(preferences: preferences, output: SystemConsoleOutput())
preferencesLogger.log()
NSUserDefaults.standardUserDefaults().removeObjectForKey("Username")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment