Как издеваться над функциями из базы? - PullRequest
0 голосов
/ 20 мая 2018

Я вызываю функцию из базы в своем коде и хочу смоделировать эту функцию в моем testthat модульном тесте.

Как я могу это сделать?

library(testthat)

my.func <- function() {
  return(Sys.info()["sysname"])   # e. g. "Linux"
}

my.func()
# sysname 
# "Linux" 

test_that("base function can be mocked",
  with_mock(
    Sys.info = function() return(list(sysname = "Clever OS")),  # see edit 2 !!!
    expect_equal(my.func(), "Clever OS", fixed = TRUE)
  )
)
# Error: Test failed: 'base function can be mocked'
# * my.func() not equal to "Clever OS".

?with_mock говорит:

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

Я мог бы инкапсулировать вызов базовой функциив Sys.info() с помощью функции-обертки, которую я затем вызываю из my.func, но давайте предположим, что я не могу этого сделать, потому что я тестирую функцию из пакета, который я не могу изменить ...

Есть какое-либо решение для этого?

Я использую 64-битный R3.4.4 в Ubuntu 14.04 с тестом 2.0.0.9000.

Редактировать 1:

Используя

`base::Sys.info` = function() return(list(sysname = "Clever OS"))

приводит к сообщению об ошибке testthat:

Невозможно смоделировать функции в базовых пакетах (базовые)

Редактировать 2: Как показывает @uren в своем ответе, мой пример кода здесь неправильный (смоделированная функция возвращает другой класс, а не исходный: - (

CorreФункция ct mock должна быть: Sys.info = function() return(c(sysname = "Clever OS"))

Ответы [ 2 ]

0 голосов
/ 21 мая 2018

Предупреждение о ложных базовых функциях с использованием with_mock:

Несмотря на то, что в случае моего вопроса и принятого ответа @Suren многие вопросы вокруг * 1006 могут сработать при базовых функциях.* в пакете testthat не рекомендуется использовать функции базового пакета (или даже функции вне тестируемого пакета), например,

testthat 2.0.0 - прерывание изменений API

  • «Не могу смоделировать функции в базовых пакетах»: вы больше не можете использовать with_mock () для имитации функций в базовых пакетах, потому что это больше не работает в R-devel из-за изменений с компилятором байт-кода. Я рекомендую вместо этого использовать mockery или mockr.

Не разрешать использование базовых пакетов

Функция with_mock (), похоже, плохо взаимодействует с JIT-компиляторомзаглушка, которая использует другой подход к тому, чтобы высмеивать вещи, которые не ограничены проблемами, поднятыми в других потоках.Если with_mock прервется, я думаю, что этот пакет будет работать так же хорошо с насмешкой.Я также думаю, что насмешка была бы разумным местом для размещения with_mock, где она могла бы жить рядом с заглушкой по унаследованным причинам.

Запретить with_mock прикасаться к базовым пакетам R

0 голосов
/ 21 мая 2018

Сообщение об ошибке: my.func () не равно "Умная ОС". .Причина в том, что Sys.info возвращает именованный символьный вектор, в то время как ваша функция насмешки a list.

Просто измените функцию насмешки и ожидаемое значение, и она будет работать:

test_that("base function can be mocked",
  with_mock(
    Sys.info = function() return(c(sysname = "Clever OS")),
    expect_equal(my.func(), c(sysname = "Clever OS"), fixed = TRUE)
  )
)

Этоработает даже в пакете.

Примечание. Копирование базовых функций не должно работать согласно справке with_mock, но работает (по крайней мере, на данный момент).

Следующее (my.func () $ `sysname`), кажется, прошло тест с оригинальным кодом из вопроса.

test_that("base function can be mocked",
          with_mock(
            Sys.info = function() return(list(sysname = "Clever OS")), 
            expect_equal(my.func()$`sysname`, "Clever OS", fixed = TRUE)
          )
)

В качестве альтернативы, есть список, где строка в expect_equal

test_that("base function can be mocked",
          with_mock(
            Sys.info = function() return(list(sysname = "Clever OS")),  
            expect_equal(my.func(), list(`sysname` = "Clever OS"), fixed = TRUE)
          )
)
...