2013-12-14 2 views
4

У меня есть простая структура данных для проверки в smallcheck.Haskell/SmallCheck: как управлять параметром `Depth`?

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} 
{-# LANGUAGE DeriveGeneriC#-} 

import Test.Tasty 
import Test.Tasty.SmallCheck 
import Test.SmallCheck.Series 
import GHC.Generics 

data T1 = T1 { p1 :: Int, 
       p2 :: Char, 
       p3 :: [Int] 
      } deriving (Eq, Show, Generic) 

instance Monad m => Serial m T1 

main :: IO() 
main = defaultMain tests 

tests :: TestTree 
tests = testGroup "Tests" [scProps] 

scProps = testGroup "(checked by SmallCheck)" 
    [ testProperty "Test1" prop_test1 
    ] 

prop_test1 x = x == x 
      where types = (x :: T1) 

При выполнении тестов есть ли общее решение установить параметр Depth для (индивидуальных) испытаний, или еще лучше, мелкозернистое решение установить параметр Depth для отдельных полей, например, ограничить глубину p3 до 2, чтобы избежать комбинаторного взрыва поискового пространства?

Большое спасибо заранее!

Жюль

информация: Несколько связан вопрос here.

EDIT:
Я принял решение, указанное в принятом ответе на Roman Cheplyaka и реализовал их в минимальном рабочем примере (спасибо, римский):

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} 

import Test.Tasty 
import Test.Tasty.Options 
import Test.Tasty.SmallCheck 
import Test.SmallCheck.Series 
import Data.Functor 
-- ============================================================================= 
main :: IO() 
main = defaultMain tests 
-- ============================================================================= 
-- the data structure to be tested 
data T1 = T1 { p1 :: Int, 
       p2 :: Char, 
       p3 :: Int, 
       p5 :: [Int] 
      } deriving (Show, Eq) 
-- ============================================================================= 
-- some test-properties 
prop_test1 x y = x == y 
       where types = (x :: T1, y :: T1) 
prop_test2 x = x == x 
      where types = (x :: T1) 
-- ============================================================================= 
-- how to change the depth of the search spaces? 
{-| I Possibility: Command Line |-} 
-- [email protected]$ runhaskell Test.hs --smallcheck-depth 2 

-- ----------------------------------------------------------------------------- 
{-| II Possibility: |-} 
-- normal: 
-- tests :: TestTree 
-- tests = testGroup "Tests" [scProps] 

-- custom: 
tests :: TestTree 
tests = localOption d $ testGroup "Tests" [scProps] 
     where d = 3 :: SmallCheckDepth 

scProps = testGroup "(checked by SmallCheck)" 
    [ testProperty "Test1" prop_test1, 
    testProperty "Test2" prop_test2 
    ] 

-- ----------------------------------------------------------------------------- 
{-| III Possibility: Adjust Depth when making the type instance of Serial |-} 
-- normal: 
-- instance (Monad m) => Serial m T1 where 
-- series = T1 <$> series <~> series <~> series <~> series 

-- custom: 
instance (Monad m) => Serial m T1 where 
    series = localDepth (const 4) $ T1 <$> (localDepth (const 2) series) <~> series <~> series <~> (decDepth series) 

-- (a few more examples): 
-- instance (Monad m) => Serial m T1 where 
-- series = decDepth $ T1 <$> series <~> series <~> series <~> (decDepth series) 
-- instance (Monad m) => Serial m T1 where 
-- series = localDepth (const 3) $ T1 <$> series <~> series <~> series <~> series 
-- instance (Monad m) => Serial m T1 where 
-- series = localDepth (const 4) $ T1 <$> series <~> series <~> series <~> (decDepth series) 
+0

См. Http://stackoverflow.com/questions/15959357/quickcheck-arbitrary-instances-of-nested-data-structures-that-generate-balanced - Я искал ответ на это всего пару часов назад и наткнулся на эту ссылку. – identity

+0

@jules относительно вашего редактирования, я хотел бы указать, что нет необходимости выбирать только один путь и выталкивать эту глубину вниз (хотя вы можете, если хотите). Эти элементы управления прекрасно выглядят, если вы используете относительные функции ('adjustOption',' localDepth' без 'const'). В частности, используя 'localDepth. const' в SmallCheck редко бывает хорошей идеей. –

ответ

3

Я начну с перечислением средств из-под контроля, что вкусно & smallcheck обеспечить из коробки:

  • когда работает на Эст люкс, вы можете передать опцию --smallcheck-depth, чтобы контролировать «общую» Глубину
  • при написания тестового набора, вы можете использовать adjustOption для регулировки глубины для любого поддерева относительно того, что было указаны в командной строке (или для родительских деревьев)
  • , наконец, при написании серийных экземпляров вы можете использовать localDepth, чтобы настроить глубину, необходимую для каждого конкретного поля, относительно глубины всей структуры. Обычно это общая глубина - 1 (это то, что делает decDepth в стандартных определениях), но вы можете придумать свои собственные правила.

Таким образом, такой контроль возможен, хотя и косвенным образом. Обычно это то, что вы хотите в любом случае - см. Также this answer.

Если вы действительно хотите контролировать глубину отдельных полей во время выполнения ... да, это возможно, хотя это немного сложно, потому что это был не предполагаемый прецедент. (Тем не менее, это довольно здорово, что это возможно вообще!) Here's a working example.

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

1

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

При запуске тестового набора (исполняемый) непосредственно:

./test --smallcheck-depth 2 

При запуске тестового набора из междусобойчик:

cabal test --test-options="--smallcheck-depth 2" 

Путем изменения глубины в TestGroup/TestTree:

-- Global depth + 1 (usually supplied by command line) 
props = adjustOption (+ SmallCheckDepth 1) $ 
     testGroup "some props" 
      [ SC.testProperty myProp1 
      , SC.testProperty myProp2 
      ] 

-- Local depth = 2 
prps2 = localOption (SmallCheckDepth 2) $ 
     testGroup "fixed depth" 
     [ ... ] 

adjustOption и localOption также могут быть использованы для конкретных целей эс. Я лично считаю, что configureOption предпочтительнее, поскольку он просто настраивает все, что предоставляется в командной строке или в любом приложении TestTree.

+0

Обратите внимание на уменьшение глубины: используйте '' adjustOption (вычесть $ SmallCheckDepth 1) '' как '-' [нельзя использовать непосредственно в разделе] (http://www.haskell.org/haskellwiki/Section_of_an_infix_operator). –