Как мы можем тестировать функции, которые не отображаются при создании пакетов R?

В настоящее время я разрабатываю графический пакет анализа для R. Мы пытаемся использовать принципы как из Очистить код и Test-Driven Development (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), мы даже не пытаемся их протестировать.
  • Hadley Wickham testthat package wiki говорит, что поддерживает тестирование "неэкспортированных функций" с использованием рабочего процесса R CMD check.
  • Если все остальное не удается, мы могли бы как-то вручную разбить наши функции Outer() для целей тестирования

Ни одно из этих решений не работает до сих пор

Решение 1 похоже на копирование. Мы считаем, что особенно в R, разумно иметь функцию верхнего уровня, которая вызывает различные короткие, однопользовательские методы полезности. Невозможность протестировать такие методы кажется глупым, и вроде того, что там есть решение, но мы еще не нашли его.

Решение 2 может работать, но до сих пор мы не работали. Если вы попытаетесь клонировать наш репозиторий, то sourcing inst/dev.R Я считаю, что вы найдете в тестовом выходе, что он не может найти функцию InitializeGgplot(), хотя указанная функция определена в строках 613-615 granova.1w.ggplot(). Точно так же запуск R CMD check на терминале вообще не выполняется ни одним из наших тестов. Это занимает много времени и набрасывает на нас оскорбительные ошибки: - (

Решение 3 в некотором смысле прагматично, но противоречит цели всегда двигаться к цели цели проекта. Это не имеет смысла для нас.

Каким будет идеальное решение

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

Итак, что нам не хватает? Должны ли методы TDD разрешать тестирование настроек внешнего/внутреннего стиля в R? Если да, то как мы можем это сделать при разработке нашего пакета? Любая обратная связь приветствуется, и я постараюсь ответить на все, что неясно.

Спасибо!

Ответы

Ответ 1

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

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

Ответ 2

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