user1198582
user1198582

Reputation:

Controlling how test data is generated in QuickCheck 2

I have a problem similar to this question Controlling how test data is generated in QuickCheck. Below I will articulate my specifics, the code I am using, and the particular question I have.

I have written a fizz-buzz program that uses a Fibonacci sequence as input. I would like to test two things. (1) Does my program emit the correct string given an Int that meets a particular condition. (2) Is my Fibonacci generator generating Fibonacci numbers?

The problem I am having is similar to the link above. The range of Ints is too large. How do I constrain my tests to say, the first 1000 Fibonacci numbers?

Here is code that I think is both adequate and minimal. Please let me know if I need to elaborate.

import           Data.Numbers.Primes (isPrime)
import           Test.Hspec  (Spec,hspec,describe,it,shouldBe)
import           Test.Hspec.QuickCheck (prop)

qcheck :: Spec
qcheck = do
  describe "QuickCheck test fiz" $
    prop "QuickCheck test" $ modfiz

  describe "QuickCheck test fib" $
    prop "QuickCheck test fib" $ testfib

modfiz int
  | int <= 0                                 = True  -- code smell, should never generate number less than or equal to zero.
  | int == 3                                 = test3
  | int == 5                                 = test5
  | int `mod` 15 == 0                        = testMod35
  | int `mod` 3 == 0                         = testMod3
  | int `mod` 5 == 0                         = testMod5
  | isPrime int == True                      = testPrime
  | otherwise                                = testRest
      where
        test3     =
          Right "Buzz BuzzFizz"     == fizzbuzz 3
        test5     =
          Right "Fizz BuzzFizz"     == fizzbuzz 5
        testMod3  =
          Right "Buzz "             == fizzbuzz int
        testMod5  =
          Right "Fizz "             == fizzbuzz int
        testMod35 =
          Right "Buzz Fizz "        == fizzbuzz int
        testPrime =
          Right "BuzzFizz"          == fizzbuzz int
        testRest  =
          Right (show int)          == fizzbuzz int

testfib :: Integer -> Bool
testfib n =
  case (fibb n) of
    Left _ -> False
    Right n' -> isFib n'

fibb takes an Int and finds that nth Fibonacci. So fibb 6 would return Right 8. The Left value is not relevant to this problem.

What I noticed was the answer suggested that one should write a newtype, wrapping a [Int] and making a new Arbitrary instance. However, I also noticed that the answer is from 2012, and QuickCheck 2 has an Args datatype that appears to be able to do what I need. So, can I create a new Args to limit the range of tests, (just want the first 1000 Fibonacci numbers), and also to limit the number of tests run? If not is the solution from the above link the approach I would have to take?

the entire project here

Upvotes: 2

Views: 274

Answers (1)

user1198582
user1198582

Reputation:

while finding out about the Bounded typeclass was useful for another project, I have agreed with opinions from the Haskell Cafe 1 mailing list Int in a newtype is heavy-handed and so have decided to solve the problem in the following way.

qcheck :: Spec
qcheck = do
  describe "QuickCheck testing fizbuzz"     $
    modifyMaxSuccess (const 1000)           $
    prop  "Lowerbound: 0 Upperbound: 10000" $
    forAll (choose (1, 10000)) modfiz

  describe "QuickCheck test fibonacci generator" $
    modifyMaxSuccess (const 1000)                $
    prop "Lowerbound: 0 Upperbound: 10000"       $
    forAll (choose (1, 10000)) testfib

1 https://groups.google.com/forum/#!topic/haskell-cafe/y81Q5fXil34

Upvotes: 1

Related Questions