【译】如何用Swift进行TDD(测试驱动开发)

【译】如何用Swift进行TDD(测试驱动开发)_第1张图片

本文由CocoaChina译者 @ALEX吴浩文 翻译

原文:How can you do TDD with Swift?


如果你还没有用类似Swift的编译型语言进行过TDD,你可能想问:如果测试引用的对象不存在,你怎么进行代码编译,又怎么进行TDD呢?

相对于类似Swift的编译型语言,类似Ruby和JavaScript的解释型语言可能天生更适合TDD,因为你可以编写不存在的测试对象,并且不会产生编译错误。

所以该如何用编译型语言进行TDD?

你可以直接编写测试代码,放任它编译失败。如果你把“编译失败”当作解释型语言的测试失败,就简单多了。失败就是失败,无论是由于编译器还是你的测试。

为了说明这一点,我们对Project类进行TDD,我们希望创建一个它的字典,这样之后可以进行序列化。

1、创建一个测试和你想要存在的实例

因为我们想要测试的是创建一个Project的字典,我们需要一个Project的实例(当前它并不存在)。

class ProjectTests: XCTestCase {
    func test_asDictionary() {
        let project = Project(id: 5)
    }
}

编译失败,所以测试失败了。我们有一个好的开始,说真的,这就是TDD——我们希望我们的第一个测试是失败的。

测试状态:红色。

2、编写你想要存在的类

为了解决编译错误,Project需要一个有id参数的init,代码如下:

class Project { 
    private let id: Int
    
    init(id: Int) {
        self.id = id
    }
}

这修复了编译错误,所以测试通过。

测试状态:绿色。

3、在测试中,调用你想要存在的方法

现在我们想用Project实例调用asDictionary方法,这个方法将给我们Project的字典表示。

func test_asDictionary() {
    let project = Project(id: 5)
    let dict = project.asDictionary()
}

编译失败,所以测试状态为红色。好,我们可以继续进行。

测试状态:红色。

4、编写你想要存在的方法

在Project类里,我们现在可以实现asDictionary方法了,但是注意我们要用最简短的代码来通过测试。(换句话说,不要用的id属性!)

func asDictionary() -> [String: AnyObject] {
    return [String: AnyObject]()
}

记住,在TDD过程中,我们总是试图做最简单的事情来通过测试。所以这里我们只返回一个空的字典——我们暂时不需要任何键或值,因为没有失败的测试告诉我们这样做。

这使得测试状态为绿色,因为它修复了编译错误。当然,我们的测试还不告诉我们很多信息,所以我们需要写一个断言。

测试状态:绿色。

5、在测试里,编写一个断言

现在我们可以在asDictionary方法的返回值里做断言。我们希望Project的id出现在字典里。所以我们的测试变成了这样:

func test_asDictionary() {
    let project = Project(id: 5)
    let dict = project.asDictionary()
        
    XCTAssertEqual(dict["id"] as? Int, 5)
}

这通过了编译,但是运行的时候,测试失败了,它告诉我们nil并不等于5。我们的测试再次失败,但没关系,我们可以修复它!

测试状态:红色。

6、实现方法,来通过测试

现在我们可以编写方法逻辑,履行断言,使测试通过。

回到我们的Project,我们可以更新asDictionary:

func asDictionary() -> [String: AnyObject] {
    return ["id": 5]
}

什么?你可能会想,现在我们不是应该返回id而不是5吗?如果我们真的在实行TDD,那就不应该,我们不应该返回id属性的值。返回硬编码值5在这里是最简单的通过测试的方法。如果我们想断言返回的字典里有id,我们需要另一个测试。

测试状态:绿色。断言状态:不够好。

7、编写另一个测试,下一个新的断言

现在我们可以编写一个完整的测试,并且没有任何编译错误。我们会创建一个新的测试,其中Project的id能给出除5以外的一个值,调用asDictionary,下断言。

func test_asDictionary_with_id_7() {
    let project = Project(id: 7)
    let dict = project.asDictionary()
        
    XCTAssertEqual(dict["id"] as? Int, 7)
}

这将会编译失败,因为asDictionary的id值总是5。这很好,因为现在我们有一些不错的断言告诉我们代码应该如何工作。

测试状态:红色。断言状态:好。

8、实现方法,使测试通过

现在我们可以更新asDictionary使我们的测试通过。但是这一次,返回一个硬编码["id": 7]并没有用,因为这将打破我们的第一个测试。我们可以修改这个方法来返回字典里的id值,像这样:

func asDictionary() -> [String: AnyObject] {
    return ["id": id]
}

当我们运行测试,他们通过了!现在我们可以相信asDictionary将始终返回字典里的id。

测试状态:绿色。断言状态:好。

结论

你可以用类似Swift的编译型语言实践TDD——事实上, Test Driven Development: By Example(这本书继续谈了TDD)使用了Java这个编译型语言来说明如何进行TDD。只要你以同样的方式对待编译错误和解释型语言的测试失败,TDD过程是完全相同的。


你可能感兴趣的:(SWIFT)