почему quickCheck создает списки единиц - PullRequest
2 голосов
/ 12 мая 2019

Я попробовал следующее из статьи QuickCheck Testing для удовольствия и прибыли.

prop_revApp xs ys = reverse (xs ++ ys) == reverse xs ++ reverse ys

и прошло, хотя не должно было. Я запустил verboseCheck, и я вижу, что он проверяет только списки единиц, т.е.

Passed:
[(),(),(),(),(),(),(),(),(),(),(),(),(),()]

Мне было интересно, почему это так.

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

1 Ответ

2 голосов
/ 12 мая 2019

Функция prop_revApp довольно общая:

*Main> :t prop_revApp
prop_revApp :: Eq a => [a] -> [a] -> Bool

Если вы просто загружаете код в GHCi и запускаете его, да, действительно, свойство передает:

*Main> quickCheck prop_revApp
+++ OK, passed 100 tests.

Это потому, что GHCi поставляется с набором предпочтительных значений по умолчанию.Для удобства он попытается использовать самый простой из возможных типов.

Он не намного проще, чем (), и, поскольку () имеет экземпляр Eq, он выбирает его.

Если, с другой стороны, вы на самом деле пытаетесь написать и скомпилировать некоторые свойства, код не скомпилируется:

import Test.Framework (defaultMain, testGroup)
import Test.Framework.Providers.QuickCheck2 (testProperty)

import Test.QuickCheck

main :: IO ()
main = defaultMain tests

prop_revApp xs ys = reverse (xs ++ ys) == reverse xs ++ reverse ys

tests = [
        testGroup "Example" [
                testProperty "prop_revApp" prop_revApp
           ]
      ]

Если вы попытаетесь запустить эти тесты с stack test,вы получите ошибку компилятора:

test\Spec.hs:11:17: error:
    * Ambiguous type variable `a0' arising from a use of `testProperty'
      prevents the constraint `(Arbitrary a0)' from being solved.
      Probable fix: use a type annotation to specify what `a0' should be.
      These potential instances exist:
        instance (Arbitrary a, Arbitrary b) => Arbitrary (Either a b)
          -- Defined in `Test.QuickCheck.Arbitrary'
        instance Arbitrary Ordering
          -- Defined in `Test.QuickCheck.Arbitrary'
        instance Arbitrary Integer
          -- Defined in `Test.QuickCheck.Arbitrary'
        ...plus 19 others
        ...plus 61 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    * In the expression: testProperty "prop_revApp" prop_revApp
      In the second argument of `testGroup', namely
        `[testProperty "prop_revApp" prop_revApp]'
      In the expression:
        testGroup "Example" [testProperty "prop_revApp" prop_revApp]
   |
11 |                 testProperty "prop_revApp" prop_revApp
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Вам нужно будет придать свойству более конкретный тип;например,

tests = [
        testGroup "Example" [
                testProperty "prop_revApp" (prop_revApp :: [Int] -> [Int] -> Bool)
           ]
      ]

Теперь тест компилируется, но не работает:

$ stack test
Q56101904-0.1.0.0: test (suite: Q56101904-test)

Example:
  prop_revApp: [Failed]
*** Failed! Falsifiable (after 3 tests and 3 shrinks):
[1]
[0]
(used seed -7398729956129639050)

         Properties  Total
 Passed  0           0
 Failed  1           1
 Total   1           1

Q56101904-0.1.0.0: Test suite Q56101904-test failed
Test suite failure for package Q56101904-0.1.0.0
    Q56101904-test:  exited with: ExitFailure 1
Logs printed to console
...