How do I write QuickCheck tests that don't mimic implementation of the function?
Asked Answered
T

1

9

I am using Haskell and QuickCheck to write a test for the following function:

{-| Given a list of points and a direction, find the point furthest
along in that direction. -}

fn :: (Eq a, Ord a, DotProd a) => [a] -> a -> a
fn pnts dir = pnts !! index
    where index = fromJust $ elemIndex (maximum dotproducts) dotproducts
          dotproducts = map (dot dir) pnts

I believe this implementation to be correct, since it's not too complex of a function. But, I want to use QuickCheck to test it for some edge cases.

However, I run into the problem that, when I define my QuickCheck tests, they are identical to the function I am testing.

How do I write a test in QuickCheck that tests the purpose of a function without repeating its implementation?

Todd answered 16/2, 2014 at 2:8 Comment(5)
If someone feels the question is too broad, please consider this a question specifically aimed at the function fn.Todd
It would help if you shared a bit more information about your problem, such as the specific inadequate test, what you expect from it, and the source of the DotProd typeclass.Chrysler
Can you write an Arbitrary for a point? A direction? If so, what property of the randomly generated points is unsatisfactory?Riker
Please add more information so that your code is self-contained. In particular, the definition of DotProd and some its instances. It'd also help if you added the QuickCheck tests you tried.Arola
A coding tip: have a look at the maximumBy function in Data.List. Using fromJust is unsafe since it can throw an exception.Term
E
13

How do I write a test in QuickCheck that tests the purpose of a function without repeating its implementation?

First, note that sometimes, a quickcheck property that states that a function behaves according to its current implementation is not completely worthless. You can use it for regression tests if you ever change the implementation. For example, if you optimize the definition of your fn to use clever data structures, the Quickcheck property based on the old, more straight-forward implementation might prove helpful.

Second, you often want your Quickcheck properties to check high-level and declarative properties of your functions, while the implementation is usually lower-level and more directly executable. In this case, you could specify such properties as:

  • forall lists of points ps and directions d, the point fn ps d is in the list ps.

  • forall lists of points ps, directions d, and forall points p in ps, the point p is not further along in the direction d than the point fn ps d.

  • forall points p and forall directions d, fn [p, origin] d is p.

I'm not totally sure about the underlying geometry, so my examples might be stupid. But I hope the examples convey the general idea: The quickcheck properties could check for properties of the specification "being further along in a direction" without mentioning the particular algorithm.

Elison answered 16/2, 2014 at 7:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.