Мы воспользовались двумя функциями из бибилотеки QuickCheck
. Это vector и choose. Первая строитсписок случайных чисел заданной длины, а вторая выбирает случайное число из заданного диапазона. Теперь
мы можем протетстировать наши предикаты с помощью функции quickCheck:
*Test Prelude>
quickCheck prop1+++ OK
, passed 100 tests.*Test Prelude>
quickCheck prop2+++ OK
, passed 100 tests.*Test Prelude>
Свойства прошли тестирование на выборке из 100 комбинаций аргументов. Если нам интересно, мы
можем с помощью функции verboseCheck посмотреть на каких именно значениях проводилось тестирование:
Тестирование с помощью QuickCheck | 281
*Test Prelude>
verboseCheck prop2Passed:
St Black Kosmodrom
St Red UlBylichova
Passed:
St Black UlBylichova
St Orange Sever
Passed:
St Red Sirius
St Blue Krest
...
Если бы свойство не выполнилось, QuickCheck
сообщил бы нам об этом и показал бы те элементы, длякоторых свойство не выполнилось. Давайте составим такое свойство искусственно. Например, проверим,
находятся ли все станции на одной линии:
fakeProp :: Station -> Station -> Bool
fakeProp (St
a _) (St b _) = a == bПосмотрим, что на это скажет QuickCheck
:*Test Prelude>
quickCheck fakeProp*** Failed! Falsifiable
(after 1 test):St Green Sirius
St Blue Rodnik
По умолчанию QuickCheck
проверит свойство сто раз. Для изменения этих настроек, мы можем восполь-зоваться функцией quickCheckWith, дополнительным параметром она принимает значение типа Arg
, котороесодержит параметры тестирования. Например протестируем первое свойство 500 раз:
*Test>
quickCheckWith (stdArgs{ maxSuccess = 500 }) prop1+++ OK
, passed 500 tests.Мы воспользовались стандартными настройками (stdArgs) и изменили один параметр.
Формирование тестовой выборки
Предположим, что мы уверены в правильной работе алгоритма для голубой и чёрной ветки метро, но
сомневаемся в остальных. Как раз для этого случая в QuickCheck
предусмотрена функция a==> b. Это функ-ция обозначает условную проверку, свойство b будет протестировано только в том случае, если свойство a
окажется верным. Иначе тестовые данные будут отброшены.
notBlueAndBlack a b =
cond a && cond b ==> prop1 a bwhere
cond (St a _) = a /= Blue && a /= BlackДалее тестируем как обычно:
*Test>
quickCheck notBlueAndBlack+++ OK
, passed 100 tests.Также с помощью функции forAll мы можем подсказать QuickCheck
на каких данных тестировать свой-ство.
forAll ::
(Show a, Testable prop) => Gen a -> (a -> prop) -> PropertyЭта функция принимает генератор случайных значений и свойство, которое зависит от тех значений,
которые создаются этим генератором. К примеру, пусть нас интересуют только все возможные пути между
четырьмя станциями: (St Blue De
), (St Red Lao), (St Green Til) и (St Orange Sever). Воспользуемсяфункцией elements ::
[a] -> Gen a, она как раз принимает список значений, и возвращает генератор,который случайным образом выбирает любое значение из этого списка.
testFor =
forAll (liftA2 (,) gen gen) $ uncurry prop1where
gen = elements [St Blue De, St Red Lao,St Green Til
, St Orange Sever]Проверим, те ли значения попали в выборку:
282 | Глава 19: Ориентируемся по карте
*Test>
verboseCheckWith (stdArgs{ maxSuccess = 3 }) testForPassed:
(St Blue De
, St Orange Sever)Passed:
(St Orange Sever
, St Red Lao)Passed:
(St Red Lao
, St Red Lao)+++ OK
, passed 3 tests.Мы можем настроить формирование выборки ещё одним способом. Для этого мы сделаем специальный
тип обёртку над Station
и определим для ненго свой экземпляр класса Arbitrary:newtype OnlyOrange = OnlyOrange Station
newtype Only4
= Only4
Station
instance Arbitrary OnlyOrange where
arbitrary = OnlyOrange . St Orange <$>
elements [DnoBolota
, PlBakha, Krest, Lao, Sever]instance Arbitrary Only4 where
arbitrary = Only4 <$>
elements [St Blue De, St Red Lao,St Green Til
, St Orange Sever]После этого мы можем очень легко комбинировать различные выборки при тестировании.
*Test>
quickCheck $ \(Only4 a) (Only4 b) -> prop1 a b+++ OK
, passed 100 tests.*Test>
quickCheck $ \(Only4 a) (OnlyOrange b) -> prop1 a b+++ OK
, passed 100 tests.*Test>
quickCheck $ \a (OnlyOrange b) -> prop2 a b+++ OK
, passed 100 tests.