Как получить тестовое покрытие для провала заявления гвардии

Я начал писать модульные тесты iOS сегодня с подходом BDD. У меня есть вопрос относительно guard заявления и получение 100% покрытия кода.

У меня есть следующий код, который обрабатывает преобразование Data в Customer объекты.

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())
            }
        }
    }
}

Это гарантирует, что я создаю Customer когда первое имя отсутствует или присутствует в возвращенном JSON.

Как я могу получить 100% покрытие кода этого метода, используя BDD, когда мой код не достигает else пункты из guard заявления, так как данные могут быть превращены в действительные объекты JSON? Должен ли я просто добавить еще .json файл с данными, которые не могут быть преобразованы в объект JSON, чтобы гарантировать, что Customer не создан, а также .json файл, который содержит недостающий last_name чтобы убедиться, что Customer не создан?

Я просто слишком обдумываю концепцию "100% покрытия кода"? Мне даже нужно иметь else пункты из guard заявления проверены? У меня даже есть соответствующий подход с использованием метода BDD?

2 ответа

Решение

Просто напишите все, что вы хотите, в формате JSON, используя все возможные формы. Примеры:

  • Вы можете поразить вашу обработку исключений чем-то неправильным JSON.
  • Вы можете ударить самого первого guard с чем-то, что является массивом JSON, а не словарем.

Как говорится, вам нужно только указать код, который вы хотите исправить.

TDD и BDD связаны между собой. В TDD вы сначала написали бы неудачный тест. Затем вы должны написать код, который пройдет этот тест так быстро, как вы можете. Наконец, вы должны очистить свой код, чтобы сделать его лучше. Похоже, что вы добавляете тесты после завершения.

Кстати, ваши тесты были бы намного понятнее, если бы вы не использовали внешние файлы, но включили JSON прямо в свои тесты. Вот скриншот, показывающий, как я начинаю преобразование JSON. Скринкаст в Objective-C, но принципы те же: https://qualitycoding.org/tdd-json-parsing/

100% покрытие кода с помощью if let.

Иногда невозможно принудительно подготовить искаженный объект для принудительного выполнения выполнения. returnили же return nilиспользуется в guardзаявления.

Это тот случай, когда у вас интегрированы сторонние SDK, и соответствующие сторонние объекты создаются во время выполнения в методе. Например :

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

В этом случае очень тяжело, порой невозможно попасть в отдачу.

Но если покрытие кода является основным критерием , вы можете использовать if let для таких случаев . Если let дает 100% покрытие кода

Другие вопросы по тегам