如何获得Guard Statement声明的测试覆盖范围

时间:2017-01-01 22:40:56

标签: swift unit-testing bdd guard-statement

我今天开始使用BDD方法编写iOS单元测试。我对guard语句和100%代码覆盖率有疑问。

我有以下代码,用于处理DataCustomer个对象的转换。

internal final class func customer(from data: Data) -> Customer? {
    do {
        guard let jsonDictionary = try JSONSerialization.jsonObject(with: data, options: []) as? Dictionary<String, Any> else {
            return nil
        }
        var customerFirstName: String? = nil
        var customerLastName: String
        if let firstName = jsonDictionary["first_name"] as? String {
            customerFirstName = firstName
        }
        guard let lastName = jsonDictionary["last_name"] as? String else {
            return nil
        }
        customerLastName = lastName
        return Customer(firstName: customerFirstName, lastName: customerLastName)
    } catch {
        return nil
    }
}

当我们的后端创建时,一些客户只得到一个姓氏,其中包含他们的名字和姓氏。这就是客户的名字是可选的;他们的全名可能是last_name的值。

在我的代码中,客户的名字是可选的,而他们的姓氏是必需的。如果他们的姓氏没有从网络请求中收到的JSON中返回,那么我就不会创建客户。此外,如果Data无法序列化为Dictionary,则不会创建客户。

我有两个JSON文件,这两个文件都包含我用来测试两种方案的客户信息。

JSON中没有第一个名字:

{
    "first_name": null,
    "last_name": "Test Name",
}

另一个包含JSON中的名字:

{
    "first_name": "Test",
    "last_name": "Name",
}

在我的单元测试中,使用Quick和Nimble,当第一个名称不可用时,我处理Customer的创建时间:

override func spec() {
    super.spec()
    let bundle = Bundle(for: type(of: self))
    describe("customer") {
        context("whenAllDataAvailable") {
            it("createsSuccessfully") {
                let path = bundle.path(forResource: "CustomerValidFullName", ofType: "json", inDirectory: "ResponseStubs")!
                let url = URL(fileURLWithPath: path)
                let data = try! Data(contentsOf: url)
                let customer = DataTransformer.customer(from: data)
                expect(customer).toNot(beNil())
            }
        }
        context("whenMissingLastName") {
            it("createsUnsuccessfully") {
                let path = bundle.path(forResource: "CustomerMissingLastName", ofType: "json", inDirectory: "ResponseStubs")!
                let url = URL(fileURLWithPath: path)
                let data = try! Data(contentsOf: url)
                let customer = DataTransformer.customer(from: data)
                expect(customer).to(beNil())
            }
        }
    }
}

这确保我在返回的JSON中缺少或出现第一个名称时创建Customer

当我的代码没有点击else语句的guard子句时,如何使用BDD获得此方法的100%代码覆盖率,因为数据可以转换为有效JSON对象?我是否应该添加另一个.json文件,其中包含无法转换为JSON对象的数据,以确保不会创建Customer以及包含缺失{{1}的.json文件确保没有创建last_name

我只是过度思考&#34; 100%代码覆盖率&#34;概念?我是否需要测试Customer语句的else条款?我是否使用BDD方法采用了适当的方法?

2 个答案:

答案 0 :(得分:1)

只需编写您想要的任何JSON - 以您能想到的各种方式表达错误。例子:

  • 您可以使用不正确JSON的内容来处理异常处理。
  • 您可以使用JSON数组而不是字典来点击您的第一个guard

俗话说,你只需要涵盖你想要正确的代码。

TDD和BDD是相关的。在TDD中,您首先要编写一个失败的测试。然后,您可以尽快编写通过该测试的代码。最后,您需要清理代码以使其更好。看起来你在事后添加了测试。

顺便说一句,如果您没有使用外部文件,那么您的测试会更加清晰,但是将JSON直接放入您的测试中。这是一个截屏视频,展示了我如何TDD开始JSON转换。截屏视频是在Objective-C中,但原则是相同的:https://qualitycoding.org/tdd-json-parsing/

答案 1 :(得分:0)

使用 if let 实现 100% 的代码覆盖率。

有时,强制准备格式错误的对象以强制执行命中 return 语句中使用的 return nilguard 是不可行的。

当您集成了 3rd 方 SDK 并且在该方法中创建了相应的 3rd 方对象时,就会出现这种情况。 例如:

func aMethod() {
   guard let response = 3rdPartyResponse<3rdPartyInput>.createControl(with: .create(with: .someCase)) as? 3rdPartyResponse<3rdPartyInput> else { return }
}

在这种情况下,它非常困难,有时不可能达到回报。

但是如果代码覆盖率是主要标准,你可以使用 if let 来处理这种情况 Iflets 确实给出了 100%代码覆盖率