Как дразнить за тестирование в Haskell?

передать это функции

enableTxt(this)

function enableTxt(item) {
    var id = $(item).attr("id");
    alert(id);
}
37
задан Clint Miller 12 June 2009 в 02:02
поделиться

7 ответов

Зачем использовать модульное тестирование, если у вас есть Автоматическое тестирование на основе спецификаций ? Библиотека QuickCheck сделает это за вас. Он может генерировать произвольные (фиктивные) функции и данные с использованием класса типов Arbitrary .

«Внедрение зависимостей» - это вырожденная форма неявной передачи параметров. В Haskell вы можете использовать Reader или Free , чтобы добиться того же, но более Haskelly.

22
ответ дан 27 November 2019 в 04:54
поделиться

Другая альтернатива:

{-# LANGUAGE FlexibleContexts, RankNTypes #-}

import Control.Monad.RWS

data (Monad m) => ServiceImplementation m = ServiceImplementation
  { serviceHello :: m ()
  , serviceGetLine :: m String
  , servicePutLine :: String -> m ()
  }

serviceHelloBase :: (Monad m) => ServiceImplementation m -> m ()
serviceHelloBase impl = do
    name <- serviceGetLine impl
    servicePutLine impl $ "Hello, " ++ name

realImpl :: ServiceImplementation IO
realImpl = ServiceImplementation
  { serviceHello = serviceHelloBase realImpl
  , serviceGetLine = getLine
  , servicePutLine = putStrLn
  }

mockImpl :: (Monad m, MonadReader String m, MonadWriter String m) =>
    ServiceImplementation m
mockImpl = ServiceImplementation
  { serviceHello = serviceHelloBase mockImpl
  , serviceGetLine = ask
  , servicePutLine = tell
  }

main = serviceHello realImpl
test = case runRWS (serviceHello mockImpl) "Dave" () of
    (_, _, "Hello, Dave") -> True; _ -> False

Фактически, это один из многих способов создания объектно-ориентированного кода в Haskell.

16
ответ дан 27 November 2019 в 04:54
поделиться

Чтобы продолжить редактирование, спрашивающее о нескольких функциях, можно просто поместить их в тип записи и передать запись. Затем вы можете добавлять новые, просто обновляя тип записи . Например:

data FunctionGroup t = FunctionGroup { g :: Int -> Int, h :: t -> Int }

a grp ... = ... g grp someThing ... h grp someThingElse ...

Другой вариант, который может оказаться жизнеспособным в некоторых случаях, - использовать классы типов. Например:

class HasFunctionGroup t where
    g :: Int -> t
    h :: t -> Int

a :: HasFunctionGroup t => <some type involving t>
a ... = ... g someThing ... h someThingElse

Это работает только в том случае, если вы можете найти тип (или несколько типов, если вы используете классы типов с несколькими параметрами), которые являются общими для функций, но в тех случаях, когда это уместно, это даст вам красивый идиоматический Haskell.

5
ответ дан 27 November 2019 в 04:54
поделиться

Простым решением было бы изменить ваш

f x = ...

на

f2 g x = ... 

, а затем

f = f2 g
ftest = f2 gtest
1
ответ дан 27 November 2019 в 04:54
поделиться

Не могли бы вы просто передать функцию с именем g в f ? Пока g удовлетворяет интерфейсу typeOfSomeParms -> gReturnType , вы должны иметь возможность передать реальную функцию или фиктивную функцию.

например

f g = do
  ...
  g someParams
  ...

У меня нет сам использовал инъекцию зависимостей в Java, но тексты, которые я прочитал, во многом напоминают передачу функций высшего порядка, так что, возможно, это будет делать то, что вы хотите.


Ответ на редактирование: ответ ephemient лучше, если вам нужно решить проблема по-корпоративному, потому что вы определяете тип, содержащий несколько функций. Предлагаемый мной способ прототипирования - это просто передача кортежа функций без определения содержащего типа. Но тогда я почти никогда не пишу аннотации типов, так что рефакторинг не очень сложен.

3
ответ дан 27 November 2019 в 04:54
поделиться

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

Однако я хотел бы спросить, почему вы все равно чувствуете необходимость использовать фиктивные функции для модульного тестирования. Вы просто хотите продемонстрировать, что модуль, над которым вы работаете, выполняет свою работу. Поэтому сначала докажите, что ваш модуль нижнего уровня (тот, который вы хотите смоделировать) работает, а затем создайте новый модуль поверх него и продемонстрируйте, что он тоже работает.

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

Или вы просто работаете по корпоративному стандарту, который требует, чтобы модульные тесты проверяли только один модуль, а вся остальная система имитируется? Это очень плохой способ тестирования. Намного лучше строить свои модули снизу вверх, демонстрируя на каждом уровне, что модули соответствуют их спецификациям, прежде чем переходить к следующему уровню. Quickcheck - ваш друг.

1
ответ дан 27 November 2019 в 04:54
поделиться

Вы можете просто иметь две реализации ваших функций с разными именами, а g будет переменной, которая либо определена как одна, либо другая, как вам нужно.

g :: typeOfSomeParms -> gReturnType
g = g_mock -- change this to "g_real" when you need to

g_mock someParms = ... -- mock implementation of g

g_real someParms = ... -- real implementation of g
0
ответ дан 27 November 2019 в 04:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: