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")