https://github.com/rudymatela/fitspec
refine properties for testing Haskell programs
https://github.com/rudymatela/fitspec
enumerative-testing leancheck mutation-testing property-based-testing property-refinement property-testing
Last synced: 3 months ago
JSON representation
refine properties for testing Haskell programs
- Host: GitHub
- URL: https://github.com/rudymatela/fitspec
- Owner: rudymatela
- License: bsd-3-clause
- Created: 2015-06-19T14:23:38.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2025-01-30T17:07:40.000Z (12 months ago)
- Last Synced: 2025-10-05T11:25:32.682Z (3 months ago)
- Topics: enumerative-testing, leancheck, mutation-testing, property-based-testing, property-refinement, property-testing
- Language: Haskell
- Homepage: https://hackage.haskell.org/package/fitspec
- Size: 636 KB
- Stars: 75
- Watchers: 10
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
FitSpec
=======
[![FitSpec Build Status][build-status]][build-log]
[![FitSpec on Hackage][hackage-version]][fitspec-on-hackage]
[![FitSpec on Stackage LTS][stackage-lts-badge]][fitspec-on-stackage-lts]
[![FitSpec on Stackage Nightly][stackage-nightly-badge]][fitspec-on-stackage-nightly]
![FitSpec logo][fitspec-logo]
FitSpec provides automated assistance in the task of refining test properties
for [Haskell] functions. FitSpec tests mutant variations of functions under
test against a given property set, recording any surviving mutants that pass
all tests. FitSpec then reports:
* *surviving mutants:*
indicating incompleteness of properties,
prompting the user to amend a property or to add a new one;
* *conjectures:*
indicating redundancy in the property set,
prompting the user to remove properties so to reduce the cost of testing.
Installing FitSpec
------------------
To install the [latest FitSpec version from Hackage], just:
$ cabal install fitspec
Pre-requisites are [cmdargs] and [leancheck].
They should be automatically resolved and installed by [Cabal].
Starting from Cabal v3.0, you need to pass `--lib` as an argument to
`cabal install`:
$ cabal install fitspec --lib
Using FitSpec
-------------
As an example, consider the following properties describing a `sort` function:
prop_ordered xs = ordered (sort xs)
prop_length xs = length (sort xs) == length xs
prop_elem x xs = elem x (sort xs) == elem x xs
prop_notElem x xs = notElem x (sort xs) == notElem x xs
prop_min x xs = head (sort (x:xs)) == minimum (x:xs)
We provide the above properties to FitSpec in the following program:
import Test.FitSpec
import Data.List
properties sort =
[ property $ \xs -> ordered (sort xs)
, property $ \xs -> length (sort xs) == length xs
, property $ \x xs -> elem x (sort xs) == elem x xs
, property $ \x xs -> notElem x (sort xs) == notElem x xs
, property $ \x xs -> head (sort (x:xs)) == minimum (x:xs)
]
where
ordered (x:y:xs) = x <= y && ordered (y:xs)
ordered _ = True
main = mainWith args { names = ["sort xs"]
, nMutants = 4000
, nTests = 4000
, timeout = 0
}
(sort::[Word2]->[Word2])
properties
The above program reports, after a few seconds, that our property set is
apparently *neither minimal nor complete*.
$ ./fitspec-sort
Apparent incomplete and non-minimal specification based on
4000 test cases for each of properties 1, 2, 3, 4 and 5
for each of 4000 mutant variations.
3 survivors (99% killed), smallest:
\xs -> case xs of
[0,0,1] -> [0,1,1]
_ -> sort xs
apparent minimal property subsets: {1,2,3} {1,2,4}
conjectures: {3} = {4} 96% killed (weak)
{1,3} ==> {5} 98% killed (weak)
*Completeness:* Of 4000 mutants, 3 survive testing against our 5 properties.
The surviving mutant is clearly not a valid implementation of `sort`, but
indeed satisfies those properties. As a specification, the property set is
*incomplete* as it omits to require that sorting preserves the number of
occurrences of each element value: `\x xs -> count x (sort xs) == count x xs`
*Minimality:*
So far as testing has revealed, properties 3 and 4 are equivalent and property
5 follows from 1 and 3 (conjectures). It is *up to the user* to check whether
these conjectures are true. Indeed they are, so in future testing we could
safely omit properties 4 and 5.
*Refinement:* If we omit redundant properties, and add a property to kill the
surviving mutant, our refined properties are:
properties sort =
[ \xs -> ordered (sort xs)
, \xs -> length (sort xs) == length xs
, \x xs -> elem x (sort xs) == elem x xs
, \x xs -> count x (sort xs) == count x xs
]
(The implementation of `count` is left as an exercise to the reader.)
FitSpec now reports:
Apparent complete but non-minimal specification based on
4000 test cases for each of properties 1, 2, 3 and 4
for each of 4000 mutant variations.
0 survivors (100% killed).
apparent minimal property subsets: {1,4}
conjectures: {4} ==> {2,3} 99% killed (weak)
As reported, properties 2 and 3 are implied by property 4, since that is true,
we can safely remove properties 2 and 3 to arrive at a minimal and complete
propety set.
### User-defined datatypes
If you want to use FitSpec to analyse functions over user-defined datatypes,
those datatypes should be made instances of the [Listable], [Mutable] and
[ShowMutable] typeclasses. Check the Haddock documentation of each class for
how to define instances manually. If datatypes do not follow a data invariant,
instances can be automatically derived using [TH] by:
deriveMutable ''DataType
More documentation
------------------
For more examples, see the [eg](eg) and [bench](bench) folders.
For further documentation, consult the [doc](doc) folder and [FitSpec API]
documentation on Hackage.
FitSpec has been subject to a paper, see the
[FitSpec paper on Haskell Symposium 2016](https://matela.com.br/fitspec.pdf).
FitSpec is also subject to a chapter in a [PhD Thesis (2017)].
[Listable]: https://hackage.haskell.org/package/leancheck/docs/Test-LeanCheck.html#t:Listable
[Mutable]: https://hackage.haskell.org/package/fitspec/docs/Test-FitSpec.html#t:Mutable
[ShowMutable]: https://hackage.haskell.org/package/fitspec/docs/Test-FitSpec.html#t:ShowMutable
[FitSpec API]: https://hackage.haskell.org/package/fitspec/docs/Test-FitSpec.html
[leancheck]: https://hackage.haskell.org/package/leancheck
[cmdargs]: https://hackage.haskell.org/package/cmdargs
[pretty]: https://hackage.haskell.org/package/pretty
[TH]: https://wiki.haskell.org/Template_Haskell
[Cabal]: https://www.haskell.org/cabal
[Haskell]: https://www.haskell.org/
[PhD Thesis (2017)]: https://matela.com.br/thesis-rudy.pdf
[fitspec-logo]: https://github.com/rudymatela/fitspec/raw/master/doc/fitspec.svg?sanitize=true
[build-log]: https://github.com/rudymatela/fitspec/actions/workflows/build.yml
[build-status]: https://github.com/rudymatela/fitspec/actions/workflows/build.yml/badge.svg
[hackage-version]: https://img.shields.io/hackage/v/fitspec.svg
[fitspec-on-hackage]: https://hackage.haskell.org/package/fitspec
[latest FitSpec version from Hackage]: https://hackage.haskell.org/package/fitspec
[stackage-lts-badge]: https://stackage.org/package/fitspec/badge/lts
[stackage-nightly-badge]: https://stackage.org/package/fitspec/badge/nightly
[fitspec-on-stackage]: https://stackage.org/package/fitspec
[fitspec-on-stackage-lts]: https://stackage.org/lts/package/fitspec
[fitspec-on-stackage-nightly]: https://stackage.org/nightly/package/fitspec