Как протестировать 2 метода с общей логикой?
Скажем, что у меня есть 2 общедоступных метода:
func didSelect(data: Data) {
// do something
self.view.showText(textForData(data))
}
func didDismiss(data: Data) {
if data.isSomething {
self.view.showText(textForData(data))
}
...
}
private func textForData(data: Data): String {
var text: String
if data.distance == nil {
text = "..."
} else if data.distance < 1000 {
text = "\(data.distance) m"
} else {
text = "\(data.distance / 1000) km"
}
return text
}
Оба они зависят от логики форматирования textForData
.
textForData
имеет (с этой минимизированной реализацией) 3 возможных случая.
Если я проверю все возможные случаи для обеих моих публичных функций, у меня будет 6 методов тестирования, и 3 из них также будут тестировать ту же логику, которая уже была проверена другими 3.
Каков правильный способ тестирования этого?
Ps.: Я мог бы написать отдельный тест для textForData
, а в тестах для общедоступных методов я утверждаю, что вызывается textForData
, но, похоже, нарушает инкапсуляцию моего класса, и я не хочу чтобы сделать testForData
общедоступным.
Я также не хотел бы создавать отдельный класс только для моей логики textForData
, потому что в конечном итоге создаю слишком много зависимостей для этого текущего класса, и эта логика, похоже, не подходит нигде, кроме этого класса.
Ответы
Ответ 1
Здесь у вас есть несколько вариантов.
- Не тестируйте
textForData
- Дублировать поведение в каждом тесте общедоступного метода, который использует его
- Сделать
textForData
общедоступным
- Сделать открытый класс для
textForData
Точки 1 и 2 нежелательны.
Вы казались странно против пункта 3, но есть преимущества для этого. Вы сможете проверить это поведение один раз, учитывая, что вы действительно заботитесь об этом. Я не знаю Свифта, но на других языках это не так плохо, как кажется. Общий совет - это кодирование и интерфейс, а не реализация. Таким образом, открытый интерфейс этого класса будет иметь didSelect
и didDismiss
. Ваш производственный код будет выражаться в терминах этого интерфейса, что означает, что textForData
является общедоступным методом в классе, к которому вы не можете получить доступ напрямую.
Хорошая новость заключается в том, что ваши тесты могут быть написаны против реализации (на самом деле, они должны), поэтому здесь у вас будет доступ ко всем трем методам. Таким образом, вы можете проверить свое содержание.
Точка 4 похожа на точку 3, но сохраняется как отдельный класс. Я бы выбрал это, учитывая, что вы можете утверждать, что мы нарушили принцип единой ответственности в пункте 3. Чтобы скрыть это, я бы ввел вложенный класс, чтобы начать с того, что вы указали, что этот код используется только в этом примере. Опять же, ваши тесты будут иметь доступ к этому, используя те же идеи, что и выше.
Вы код движется к обнимающемуся составу, поэтому вы должны использовать такие преимущества, как небольшие классы, хорошо продуманный код и многое другое.
Ответ 2
Я считаю, что форматирование данных является собственной ответственностью. Поэтому вы должны извлечь его в свой класс.
Этот класс может быть проверен отдельно.
Ваши другие классы, которые используют этот, должны быть разделены с помощью интерфейса вместо класса напрямую. Зависимость должна быть введена (например, в constrcutor). Вы можете написать конструктор по умолчанию, создающий класс по умолчанию, чтобы упростить работу в производственном коде (плохая инъекция зависимости от мужчин).
Затем вы можете издеваться над форматировщиком и тестировать другой класс изолированно, проверяя, что метод textForData вызывается правильно.