4

I've been trying to pick up Haskell recently, but I am having some difficulty with QuickCheck2 (which I'm trying to learn while coding up the 99 problems). I've looked at this question along with related ones on the matter.

Like OP from the aforementioned question, I'm interested in finding out whether it is possible for QuickCheck2 to expect exceptions. I know this is possible with QuickCheck 1. Some googling around led me to the following version of my code to test a myLast function which returns the last element of a list:

prop_myLast :: [Int] -> Bool
prop_myLast [] = expectFailure . myLast $ []
prop_myLast xs = myLast xs == last xs

Of course, this (1) does not typecheck, since expectFailure returns a Property and (2) requires an import from v1 of QuickCheck. Regarding (1) I don't really see how to make this work - I tried looking up how to catch exceptions on my own but was met with more difficulty because this started bringing in the IO monad. With respect to (2) I don't know if bringing in the expectFailure function is a good idea in the first place - could anyone experienced with the system tell me if I'm supposed to be using components from both v1 and v2? If not, where is the analogous expectFailure for v2 of QuickCheck?

Community
  • 1
  • 1
VF1
  • 1,594
  • 2
  • 11
  • 31
  • 1
    You can change the type to `[Int] -> Property` and change the 2nd case to `property (myLast xs == last xs)`, or `myLast xs === last xs`. – user2407038 Dec 12 '14 at 05:32

1 Answers1

3

You use expectFailure like this:

prop :: Int -> Bool
prop x = x + 1 == x  -- should always be False

main = quickCheck (expectFailure prop)

However, expectFailure only tests that there is at least one test case which fails - i.e. it really expects your code to fail. You want QuickCheck to ignore any failures in the event that it passes the empty list to prop_myLast.

One way to do this is with the ==> operator:

prop_myLast :: [Int] -> Property
prop_myLast xs = not (null xs) ==> myLast xs == last xs

Another example:

prop_cubed :: Int -> Property
prop_cubed x = (x > 1) ==> x^3 > x   -- note: not true for negative values so don't
                                     --       test those cases

Quickcheck will discard generated test cases which do not match the conditional.

Update: One way of explicitly testing the [] case is:

quickCheck $ expectFailure $ seq (myLast []) True

The expression seq a True will return True unless a throws an exception or diverges.

ErikR
  • 51,541
  • 9
  • 73
  • 124
  • Thanks for the answer. Do you mind addressing the issue between using QuickCheck v1 and v2? Importing only `Test.Framework.Providers.QuickCheck2` is insufficient (`expectFailure` and `Property` seem not to be visible). Do people work with both at the same time, or is there a solution for QuickCheck2 exclusively? – VF1 Dec 12 '14 at 05:56
  • I have `QuickCheck-2.6` installed and importing `Test.QuickCheck` gives access to `expectFailure` and `Property` as well as `quickCheck`. – ErikR Dec 12 '14 at 06:17
  • Ok, I was under the impression that this was a deprecated module (pretty daring assumption, only made on the basis that it didn't have a 2 at the end), but based on your comment I think that it should be fine. – VF1 Dec 12 '14 at 06:29
  • Actually, I still seem to be having this issue, which I would appreciate an answer for: compiling gives the following issue: `No instance for (Testable b0) arising from a use of `expectFailure' The type variable `b0' is ambiguous`, and changing `myLast` to `(myLast :: [Int] -> Int)` inline didn't seem to help (unlike what some of the SO answers on that topic seemed to indicate...). – VF1 Dec 12 '14 at 06:37
  • [Here's a gist](https://gist.github.com/vlad17/581a1d9ee3b601602a8b), I trimmed off the imports - I'm also trying to do this with modules but I don't think that's causing the issues. – VF1 Dec 12 '14 at 06:49
  • I responded to the gist. – ErikR Dec 12 '14 at 07:02