iOS APP iOS Test-Driven Development by Tutorials free secti

iOS APP iOS Test-Driven Development by Tutorials free section 学习笔记-the TDD Cycle

tags: TDD day

TDD Cycle

在上一篇笔记,您了解了测试驱动的开发可以归结为一个简单的过程,称为TDD Cycle。它有四个步骤,通常被“color coded”,如下所示:
我们称它为“Red-Green-Refactor Cycle”

图片来源
颜色是什么意思?

失败时,以 Red为颜色标记通过时,以 green 为颜色标记通过后进入 Refactor阶段

不断的循环。

注意

我的笔记会直接跳过playground的章节,建议看完playground的章节再看我的笔记:
the TDD Cycle

Getting started

clone我的专案,尝试我建制专案的过程吧。
clone Alvin的专案

需求

我希望Login in 的 button ,在帐号与密码不符合规範时,是不能按的。

graph LR; button.state是disable-->|达成条件|button.state是normal
graph LR; button.state是normal-->|未达成条件|button.state是disable

Red : Write a failing test

为了让程式码有好的可读性,我们在测试的命名要注意

Test nomenclaturn

试着遵循一些TDD命名法则。我们来看看範例:

func testAppModel_whenStarted_isInInProgressState() {}

test funtion 的名称应该要描述test。test名称显示在test logs中。当发生错误时,必续邀可以立即了解问题所在。所以要避免test1,test2这种命名。
这里使用的命名方案最多包括四个部分:

所有测试必须以开头test。AppModel这表示一个AppModel正在测试的系统(sut)。whenStarted 是条件或状态变化,是条件的触发者。isInInProgressState当when发生后状态应该受到的变化。

Try it

我要测试的条件为:
当LoginPageViewController在帐号与密码都已经服合条件时,loginButton的state要是Normal的

func testLoginPageViewController_loginStateIsBothCorrect_loginButtonIsNormal(){}

接着在里面放入三个注解

    func testLoginPageViewController_loginStateIsBothCorrect_loginButtonIsNormal(){        //given        // when        //then    }

这是为了方便理解建制这个 Test的流程。

Given 在特定的条件下When 当某个行为发生时Then 预期要发生的结果

Given 帐号与密码都符合条件下

    func testLoginPageViewController_loginStateIsBothCorrect_loginButtonIsNormal(){        //given        let state:LoginState = .bothCorrect        // when        //then    }

When 当LoginPageViewController为这个状态时

    func testLoginPageViewController_loginStateIsBothCorrect_loginButtonIsNormal(){        //given        let state:LoginState = .bothCorrect        // when        sut.loginState = state        //then    }

Then loginButton的state应该要是normal。

    func testLoginPageViewController_loginStateIsBothCorrect_loginButtonIsNormal(){        //given        let state:LoginState = .bothCorrect        // when        sut.loginState = state        //then        let loginState = sut.loginPageView.loginButton.state        XCTAssertEqual(loginState, UIButton.State.normal)    }

开始测试

按下 command + U 开始测试。

结果测试错误,别担心。这是一定会遇到的流程。我们来尝试通过测试。

Green : Make the test pass

1. 写一个Loginable的 protocol

protocol Loginable {    func changeLoginButtonState(loginState:LoginState)}

2. 让 LoginPageViewController conform Loginable 这个 protocol 然后delegate也设置完成。

import UIKitprotocol Loginable {    func changeLoginButtonState(loginState:LoginState)}class  LoginPageViewController: UIViewController{    let loginPageView = LoginPageView()    public var loginState:LoginState = .bothError    //MARK: - loadView()    override func loadView() {        self.view = loginPageView        loginPageView.delegate = self    }    //MARK: - viewDidLoad()    override func viewDidLoad() {        super .viewDidLoad()    }}    //MARK: Loginableextension LoginPageViewController:Loginable{    func changeLoginButtonState(loginState: LoginState) {        if loginState == .bothCorrect {            loginPageView.loginButton.isEnabled = true        }    }}

但是仅仅这样是不够的,我还要能够监测UITextField有没有输入文字,加入UITextField输入的delegate。

import UIKitprotocol Loginable {    func changeLoginButtonState(loginState:LoginState)}class  LoginPageViewController: UIViewController{    let loginPageView = LoginPageView()    public var loginState:LoginState = .bothError{        didSet{            changeLoginButtonState(loginState: self.loginState)        }    }        //MARK: - loadView()    override func loadView() {        self.view = loginPageView        loginPageView.loginableDelegate = self        loginPageView.usernameTextField.delegate = self        loginPageView.passwordTestField.delegate = self    }    //MARK: - viewDidLoad()    override func viewDidLoad() {        super .viewDidLoad()    }}    //MARK: Loginableextension LoginPageViewController:Loginable{    func changeLoginButtonState(loginState: LoginState) {        if loginState == .bothCorrect {            loginPageView.loginButton.isEnabled = true        }    }}extension LoginPageViewController:UITextFieldDelegate{    func textFieldDidEndEditing(_ textField: UITextField) {        if textField.text!.count > 10{            loginState = .bothCorrect            changeLoginButtonState(loginState: loginState)        }    }}

接着 command + U 再测试一次

很好,测试成功了。

3. 接下来,进入 Refactor 的流程

我重构了LoginPageViewController,将判断帐号与密码是否输入的逻辑切出去。

import UIKitprotocol Loginable {    func changeLoginButtonState(loginState:LoginState)}class  LoginPageViewController: UIViewController{    let loginPageView = LoginPageView()    public var loginState:LoginState = .bothError{        didSet{            changeLoginButtonState(loginState: self.loginState)        }    }        //MARK: - loadView()    override func loadView() {        self.view = loginPageView        loginPageView.loginableDelegate = self        loginPageView.usernameTextField.delegate = self        loginPageView.passwordTestField.delegate = self    }    //MARK: - viewDidLoad()    override func viewDidLoad() {        super .viewDidLoad()    }}    //MARK: Loginableextension LoginPageViewController:Loginable{    func changeLoginButtonState(loginState: LoginState) {        if loginState == .bothCorrect {            loginPageView.loginButton.isEnabled = true        }    }}    //MARK: UITextFieldDelegateextension LoginPageViewController:UITextFieldDelegate{    func textFieldDidEndEditing(_ textField: UITextField) {        let tag = textField.tag        if textField.text!.count > 10{           loginState =  loginState.updateState(tag: tag)        }    }}
再一次的 unit test

如果验证是成功的,代表重构是成功的。

开始

我们完成了一次 TDD Cycle,别忘了 TDD 是迭代开发软体的方法,所以这只是第一步,这或许是很漫长的,但是每个扎实的步伐,将会带领你的程式码步向于完美。
下一个 TDD Cycle


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章