Как мы можем тестировать функции, которые не отображаются при сборке пакетов R? - PullRequest
15 голосов
/ 18 мая 2011

В настоящее время я разрабатываю пакет графического анализа для R. Мы пытаемся использовать принципы как Чистый код , так и Разработка через тестирование ( TDD). Но мы столкнулись с концептуальной проблемой.

Как проверить неэкспонированные функции?

Рассмотрим следующий упрощенный пример. Outer() - это функция, которую мы создаем в нашем пакете , и мы предоставляем ее пользователям, перечисляя ее в файле NAMESPACE. Inner() - короткая (~ 5 строка) служебная функция:

Outer <- function(...) {

  Inner <- function(...) {
    return(x)
  }

  return( Inner() )
}

Большинство предоставляемых пользователем функций в нашем пакете представляют собой наборы коротких функций с одинарным стилем поведения Inner(), которые лежат под эгидой одной Outer() функции, которую может вызвать пользователь. Granova.ds.ggplot() является одним примером. Такая модульная конструкция настоятельно поддерживается Clean Code , и мы весьма довольны результатами. Но мы не знаем, как создавать для него модульные тесты, поскольку функции, которые мы хотим протестировать, недоступны вне области действия Granova.ds.ggplot(), учитывая, как мы ее спроектировали.

Нам пришло в голову несколько идей / решений:

  1. Тесты должны иметь доступ только к общедоступным API. Поскольку такие функции, как Inner(), по своей природе не являются общедоступными (они не экспортируются в NAMESPACE), мы даже не должны пытаться их проверять.
  2. Вики-пакет testthat Хэдли Уикхема говорит, что поддерживает тестирование "неэкспортируемых функций" с использованием R CMD check рабочего процесса.
  3. Если ничего не помогло, мы могли бы как-то вручную отключить наши 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? Если они это сделают, как мы можем сделать это при разработке нашего пакета? Любые отзывы приветствуются, и я постараюсь ответить на все, что неясно.

Спасибо!

Ответы [ 2 ]

7 голосов
/ 18 мая 2011

Если Inner реализует нетривиальную функциональность, которую вы хотите протестировать, я бы предложил переместить Inner на верхний уровень, но не экспортировать ее.Как правило, я избегаю вложения функций в другие функции именно по этой причине - их сложно тестировать.

Вы можете тестировать во время разработки с помощью обычных функций testthat, потому что вы, вероятно, просто используете весь код R ине беспокоиться о пространствах имен (по крайней мере, так я развиваюсь).Затем вы используете R CMD check в сочетании с test_package, чтобы гарантировать, что тесты все еще работают во время сборки - test_packages запускает тесты в пространстве имен пакета, чтобы они могли тестировать неэкспортированные функции.

6 голосов
/ 18 мая 2011

ИМО здесь не проблема - Inner - это просто неотъемлемая часть Outer, поэтому тестирование Outer проверяет Inner Хотели бы вы протестировать анонимные функции? То же самое и здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...