24. 17
模擬 login API ⾏行行為
protocol LoginAPIDelegate {
func loginToken(token:String?,callback:@escaping loginAPICompletion)
}
extension API:LoginAPIDelegate{
func loginToken(token:String?,callback:@escaping loginAPICompletion{
// call real API here
}
}
17
25. 17
模擬 login API ⾏行行為
protocol LoginAPIDelegate {
func loginToken(token:String?,callback:@escaping loginAPICompletion)
}
class MockLoginAPI:LoginAPIDelegate {
func loginToken(token:String?,callback:@escaping loginAPICompletion {
//use mock response here
}
}
extension API:LoginAPIDelegate{
func loginToken(token:String?,callback:@escaping loginAPICompletion{
// call real API here
}
}
17
26. 18
模擬 Facebook SDK response ⾏行行為
protocol FBLoginManagerDelegate {
var currentAccessToken:String? { get }
}
class FBLoginManager:FBLoginManagerDelegate {
var currentAccessToken:String? {
return FBSDKAccessToken.current()?.tokenString
}
}
class MockFBLogin:FBLoginManagerDelegate {
var currentAccessToken: String?
}
27. 19
class LoginManager{
weak var delegate:LoginManagerDelegate?
private var loginAPI:LoginAPIDelegate
private let accountKit:AccountKitDelegate
private let fb:FBLoginManagerDelegate
init(api:LoginAPIDelegate = API.shareInstance,
ac:AccountKitDelegate = AKFAccountKit(responseType: .accessToken),
fblogin:FBLoginManagerDelegate = FBLoginManager()) {
self.loginAPI = api
self.accountKit = ac
self.fb = fblogin
}
}
Real Instance
45. 30
class LoginManager{
static let shareInstance = LoginManager()
weak var delegate:LoginManagerDelegate?
private var loginAPI:LoginAPIDelegate
private let accountKit:AccountKitDelegate
private let fb:FBLoginManagerDelegate
init(api:LoginAPIDelegate = API.shareInstance,
ac:AccountKitDelegate = AKFAccountKit(responseType: .accessToken),
fblogin:FBLoginManagerDelegate = FBLogInManager()) {
self.loginAPI = api
self.accountKit = ac
self.fb = fblogin
}
}
Real Instance
51. 33
User
UserInfo
UserSetting
User Info save in memory
Ex:User ID, Member Ship
User Setting save in NSUserDefault
Ex:IsShowXXPage
When UserInfo change , some UserSetting Variable also change
Requirement
AppDelegate
53. 35
class UserInfo {
private var userSetting:UserSettingDelegate
init(userSetting:UserSettingDelegate = shareAppDelegate.user.setting){
self.userSetting = userSetting
}
}
User UserInfoAppDelegat
User UserSettingAppDelegate
54. 36
class UserInfo {
private var userSetting:UserSettingDelegate
init(userSetting:UserSettingDelegate = shareAppDelegate.user.setting){
self.userSetting = userSetting
}
}
User UserInfoAppDelegat
User
UserSetting
AppDelegate
UserInfo
55. 37
class UserInfo {
private var userSetting:UserSettingDelegate
init(userSetting:UserSettingDelegate = shareAppDelegate.user.setting){
self.userSetting = userSetting
}
}
User UserInfoAppDelegat
User
UserSetting
AppDelegate
UserInfo
User UserSettingAppDelegate
56. 38
class UserInfo:{
private var injectFunc:()->UserSetting
private var setting:UserSetting {
return self.injectFunc()
}
init(injectFunc:@escaping ()->UserSetting =
{return shareDelegate.user.setting}){
self.injectFunc = injectFunc
}
}
57. 38
class UserInfo:{
private var injectFunc:()->UserSetting
private var setting:UserSetting {
return self.injectFunc()
}
init(injectFunc:@escaping ()->UserSetting =
{return shareDelegate.user.setting}){
self.injectFunc = injectFunc
}
}
stored property
58. 38
class UserInfo:{
private var injectFunc:()->UserSetting
private var setting:UserSetting {
return self.injectFunc()
}
init(injectFunc:@escaping ()->UserSetting =
{return shareDelegate.user.setting}){
self.injectFunc = injectFunc
}
}
stored property
computed property
59. 38
class UserInfo:{
private var injectFunc:()->UserSetting
private var setting:UserSetting {
return self.injectFunc()
}
init(injectFunc:@escaping ()->UserSetting =
{return shareDelegate.user.setting}){
self.injectFunc = injectFunc
}
}
self.setting
stored property
computed property
65. 44
相關閱讀
• wwdc 2017 session 414: Engineering for Testability
• Test-Driven iOS Development with Swift 4
• Working Effectively with Legacy Code
• The Art of Unit Testing