Как получить тестовое покрытие для провала заявления гвардии
Я начал писать модульные тесты 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% покрытие кода