В настоящее время я разрабатываю пакет графического анализа для R. Мы пытаемся использовать принципы как Чистый код , так и Разработка через тестирование ( TDD). Но мы столкнулись с концептуальной проблемой.
Как проверить неэкспонированные функции?
Рассмотрим следующий упрощенный пример. Outer()
- это функция, которую мы создаем в нашем пакете , и мы предоставляем ее пользователям, перечисляя ее в файле NAMESPACE
. Inner()
- короткая (~ 5 строка) служебная функция:
Outer <- function(...) {
Inner <- function(...) {
return(x)
}
return( Inner() )
}
Большинство предоставляемых пользователем функций в нашем пакете представляют собой наборы коротких функций с одинарным стилем поведения Inner()
, которые лежат под эгидой одной Outer()
функции, которую может вызвать пользователь. Granova.ds.ggplot()
является одним примером. Такая модульная конструкция настоятельно поддерживается Clean Code , и мы весьма довольны результатами. Но мы не знаем, как создавать для него модульные тесты, поскольку функции, которые мы хотим протестировать, недоступны вне области действия Granova.ds.ggplot()
, учитывая, как мы ее спроектировали.
Нам пришло в голову несколько идей / решений:
- Тесты должны иметь доступ только к общедоступным API. Поскольку такие функции, как
Inner()
, по своей природе не являются общедоступными (они не экспортируются в NAMESPACE
), мы даже не должны пытаться их проверять.
- Вики-пакет
testthat
Хэдли Уикхема говорит, что поддерживает тестирование "неэкспортируемых функций" с использованием R CMD check
рабочего процесса.
- Если ничего не помогло, мы могли бы как-то вручную отключить наши
Outer()
функции для целей тестирования
Пока ни одно из этих решений не сработало
Решение 1 похоже на отговорку. Мы считаем, что особенно в R разумно иметь функцию верхнего уровня, которая вызывает различные короткие, служебные методы с единственной ответственностью. Невозможность протестировать такие методы кажется глупой, и вроде того, для чего есть решение, но мы просто еще не нашли.
Решение 2 может работать, но мы до сих пор не получили его. Если вы попытаетесь клонировать наш репозиторий , то поиск inst/dev.R
Я полагаю, вы найдете в результатах теста, что он не может найти функцию InitializeGgplot()
, хотя указанная функция определена в строках 613-615 granova.1w.ggplot()
. Аналогично, запуск R CMD check
в терминале, похоже, не выполняет ни одного из наших тестов вообще. Хотя это занимает много времени и вызывает у нас оскорбительные ошибки: - (
Решение 3 в некотором смысле прагматично, но противоречит цели постоянного продвижения к целевому состоянию проекта. Это не имеет смысла для нас.
Какое было бы идеальное решение
В идеале, мы ищем способ использовать пакет, такой как testthat
, чтобы быстро обеспечить обратную связь при кодировании и позволить нам тестировать функции, подобные Inner()
, которые существуют в функциях, таких как Outer()
. Еще лучше был бы способ сделать это, не прибегая к R CMD check
, который из-за 3-й сложности некоторых наших функций запускается каждый раз почти по полной.
Итак, что нам не хватает? Должны ли практики TDD разрешать тестирование настроек внешнего / внутреннего стиля в R? Если они это сделают, как мы можем сделать это при разработке нашего пакета? Любые отзывы приветствуются, и я постараюсь ответить на все, что неясно.
Спасибо!