{"id":15042936,"url":"https://github.com/quicktheories/quicktheories","last_synced_at":"2026-04-02T02:07:32.636Z","repository":{"id":57739917,"uuid":"47613863","full_name":"quicktheories/QuickTheories","owner":"quicktheories","description":"Property based testing for Java 8","archived":false,"fork":false,"pushed_at":"2020-10-13T04:15:21.000Z","size":505,"stargazers_count":501,"open_issues_count":28,"forks_count":51,"subscribers_count":37,"default_branch":"master","last_synced_at":"2024-04-05T03:06:57.498Z","etag":null,"topics":["java-8","junit","property-based-testing","quickcheck","testing"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/quicktheories.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-08T10:01:16.000Z","updated_at":"2024-03-31T14:17:04.000Z","dependencies_parsed_at":"2022-09-01T10:51:13.007Z","dependency_job_id":null,"html_url":"https://github.com/quicktheories/QuickTheories","commit_stats":null,"previous_names":["ncr-code/quicktheories"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quicktheories%2FQuickTheories","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quicktheories%2FQuickTheories/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quicktheories%2FQuickTheories/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quicktheories%2FQuickTheories/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quicktheories","download_url":"https://codeload.github.com/quicktheories/QuickTheories/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247299831,"owners_count":20916190,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java-8","junit","property-based-testing","quickcheck","testing"],"created_at":"2024-09-24T20:48:20.757Z","updated_at":"2026-04-02T02:07:32.600Z","avatar_url":"https://github.com/quicktheories.png","language":"Java","readme":"[![Build Status](https://dev.azure.com/henrycoles/quicktheories/_apis/build/status/quicktheories.QuickTheories?branchName=master)](https://dev.azure.com/henrycoles/quicktheories/_build/latest?definitionId=2\u0026branchName=master)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.quicktheories/quicktheories/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/org.quicktheories/quicktheories)\n\n# QuickTheories\n\nProperty-based testing for Java 8.\n\nIf you were looking for QuickCheck for Java you just found it.\n\nUnlike many other systems QuickTheories supports both auto-magical shrinking and targeted search using coverage data.\n\n## What is property based testing \n\nTraditional unit testing is performed by specifying a series of concrete examples and asserting on the outputs/behaviour of the unit under test.\n\nProperty based testing moves away from concrete examples and instead checks that certain properties hold true for all possible inputs. It does this by automatically generating\na random sample of valid inputs from the possible values. \n\nThis can be a good way to uncover bad assumptions made by you and your code.\n\nIf the word \"random\" is making you feel a little nervous, don't worry QuickTheories provides ways to keep your tests repeatable.\n\n## Quick Start\n\nAdd the QuickTheories jar to your build (see the badge at the top of the page for the maven coordinates of the latest version).\n\nYou can run QuickTheories from JUnit, TestNG or any other test framework.\n\nHere we are using JUnit \n\n```java\nimport static org.quicktheories.QuickTheory.qt;\nimport static org.quicktheories.generators.SourceDSL.*;\n\npublic class SomeTests {\n\n  @Test\n  public void addingTwoPositiveIntegersAlwaysGivesAPositiveInteger(){\n    qt()\n    .forAll(integers().allPositive()\n          , integers().allPositive())\n    .check((i,j) -\u003e i + j \u003e 0); \n  }\n\n}\n```\n\nThe static import `org.quicktheories.QuickTheory.qt` provides access to the QuickTheories DSL.\n\nThe static import `org.quicktheories.generators.SourceDSL.*` provides access to a DSL that allows valid inputs to be defined.\n\nThis property looks pretty simple, it just checks that adding two integers always produces a number greater than 0.\n\nThis couldn't possibly fail could it? That would mean math was broken.\n\nIf we run this test we get something like :-\n\n```\njava.lang.AssertionError: Property falsified after 1 example(s) \nSmallest found falsifying value(s) :-\n{840226137, 1309274625}\nOther found falsifying value(s) :- \n{848253830, 1320535400}\n{841714728, 1317667877}\n{840894251, 1310141916}\n{840226137, 1309274625}\n \nSeed was 29678088851250\t\n```\n\nThe falsified theory has highlighted something that we forgot. \n\nMath works just fine, but in Java integers can overflow.\n\n\n### Without static imports\n\nIf you prefer the QuickTheories entry points can be brought into scope by implementing an interface, removing the need for static imports.\n\n```java\npublic class SomeTests implements WithQuickTheories {\n\n  @Test\n  public void addingTwoPositiveIntegersAlwaysGivesAPositiveInteger(){\n    qt()\n    .forAll(integers().allPositive()\n          , integers().allPositive())\n    .check((i,j) -\u003e i + j \u003e 0); \n  }\n\n}\n```\n\n### Less verbose\n\nThe source DSL reads nicely but can be a little verbose. Most of the core generators can also be accessed by importing `org.quicktheories.generators.Generate`. This provides simple static methods that return generators of core types.\n\n```java\nimport static org.quicktheories.generators.Generate.*;\n\n@Test\npublic void someProperty() {\n  qt()\n  .forAll(range(1, 102), constant(7))\n  .check((i,c) -\u003e i + c \u003e= 7);\n}\n\n```\n\n### Shrinking\n\nQuickTheories supports shrinking. \n\nThis means that it doesn't just find a falsifying value and stop. Instead it will try to find other smaller (or \"simpler\") values that also invalidate the theory. \n\nBy default QuickTheories will spend about 100 times more effort looking for smaller values than it did looking for the original falsifying value.\n\nThe smallest found value is reported along with a sample of any other falsifying values found along the way. \n\nThere is no guarantee that this is the smallest possible falsifying value or that others don't exist. Generally the shrunk values will be easier to understand and work with than the original un-shrunk ones – patterns might be visible in the reported values.\n\nUnlike straight QuickCheck clones QuickTheories does not require you to supply your own shrinking implementation for each type. Shrinking is performed automatically for any and all types. The mechanism by which this is achieved does not make any assumptions about the structure or implementation of the type or break encapsulation.\n\n### Seeds and repeatable tests\n\nAt the end of the report the Seed is reported. \n\nThis is the value from which all randomness is derived in QuickTheories. \n\nBy default it is set to the `System.nanoTime()` so the values will be different each time QuickTheories is run, however the seed can also be set explicitly so runs can be reproduced and deterministic.\n\nWhenever a property is falsified the seed used is reported so you can always reproduce the exact same run.\n\nIt is therefore always possible to recreate a run, and you can opt for a fully deterministic behaviour by using a single fixed seed.\n\nTwo methods are provided to set the seed.\n\nDirectly using the DSL\n\n```java\n  qt()\n  .withFixedSeed(0)\n  .forAll( . . .)\n``` \n\nOr using the `QT_SEED` system property.\n\nThe same tests can therefore be run with a fixed seed for the purpose of catching regression, or with a changing seed so that falsifying values are constantly being searched for.\n\n### Assertions\n\nOur example theory used a simple predicate, but sometimes it would be nice to take advantage of the functionality provided by assertion libraries such as [assertj](http://joel-costigliola.github.io/assertj/) and [hamcrest](https://github.com/hamcrest).\n\nThis can be done using the `checkAssert` method. \n\n```java\n  @Test\n  public void someTheory() {\n    qt().forAll(longs().all())\n        .checkAssert(i -\u003e assertThat(i).isEqualsTo(42));\n  }\n``` \t\n\t  \nAny block of code that returns void can be passed to `checkAssert`. Any unchecked exception will be interpreted as falsifying the theory.\n\n### Assumptions\n\nAs we've seen we can create theories from a pair of Gens - which produce a pair of values. \n\nIn fact we can create theories about any number of values between 1 and 4.\n\n```java\n   @Test\n  public void someTheoryOrOther(){\n    qt()\n    .forAll(integers().allPositive()\n          , strings().basicLatinAlphabet().ofLengthBetween(0, 10)\n          , lists().allListsOf(integers().all()).ofSize(42))\n    .check((i,s,l) -\u003e l.contains(i) \u0026\u0026 s.equals(\"\"));\n  }\n```\n\nIn the example above we use three Gens, as you can see QuickTheories provides ways of generating most common Java types.\n\nA Gen is just a simple function from a random number generator to a value. As we can see, the DSL provides a way to put constraints on the values we generate (e.g we will only generate positive integers and the lists in this example will only be of size 42).\n\nWhenever possible you should use the DSL to provide constraints, but sometimes you might need to constrain the domain in ways that cannot be expressed with the DSL.\n\nWhen this happens use assumptions. \n\n```java\n  @Test\n  public void someTheoryOrOther(){\n    qt()\n    .forAll(integers().allPositive()\n          , strings().basicLatinAlphabet().ofLengthBetween(0, 10)\n          , lists().allListsOf(integers().all()).ofSize(42))\n    .assuming((i,s,l) -\u003e s.contains(i.toString())) // \u003c-- an assumption\n    .check((i,s,l) -\u003e l.contains(i) \u0026\u0026 s.contains(i.toString()));\n  }\n```\n\nAssumptions further constrain the values which form the subject of the theory.\n\nAlthough we could always replace the constraints we created in the DSL with assumptions, this would be very inefficient. QuickTheories would have to spend a lot of effort just trying to find valid values before it could try to invalidate a theory.\n\nAs difficult to find values probably represent a coding error, QuickTheories will throw an error if less than 10% of the generated values pass the assumptions:\n\n```java\n  @Test\n  public void badUseOfAssumptions() {\n    qt()\n    .forAll(integers().allPositive())\n    .assuming(i -\u003e i \u003c 30000)\n    .check( i -\u003e i \u003c 3000);\n  }\n```\n\nGives\n\n```\njava.lang.IllegalStateException: Gave up after finding only 107 example(s) matching the assumptions\n\tat org.quicktheories.quicktheories.core.ExceptionReporter.valuesExhausted(ExceptionReporter.java:20)\n```  \n(Note: this assumption could have been replaced by the following: \n\n```java\n   @Test\n  public void goodUseOfSource(){\n    qt().forAll(integers().from(1).upTo(30000))\n    .check( i -\u003e i \u003c 3000);\n  }\n```\nWhich gives the following failure message: )\n```\njava.lang.AssertionError: Property falsified after 1 example(s) \nSmallest found falsifying value(s) :-\n3000\nOther found falsifying value(s) :- \n13723\n13722\n13721\n13720\n13719\n13718\n13717\n13716\n13715\n13714\n \nSeed was 2563360080237\n```  \n\n### Gens \n\nIt is likely that you will want to construct instances of your own types. You could do this within each check, but this would result in a lot of code duplication.\n\nInstead you can define a conversion function. This can be done inline, or placed somewhere convenient for reuse.\n\n```java\n  @Test\n  public void someTheoryOrOther(){\n    qt()\n    .forAll(integers().allPositive()\n          , integers().allPositive())\n    .as( (width,height) -\u003e new Widget(width,height) ) // \u003c-- convert to our own type here\n    .check( widget -\u003e widget.isValid());\n  }\n```\n\nThis works well for simple cases, but there are two problems.\n\n1. We cannot refer to the original width and height integers in our theory. So we couldn't (for example) check that the widget had the expected size.\n2. If our widget doesn't define a `toString` method it is hard to know what the falsifying values were\n\nBoth of these problems are solved by the `asWithPrecursors` method\n\n```\n  @Test\n  public void someTheoryOrOther(){\n     qt()\n    .forAll(integers().allPositive()\n          , integers().allPositive())\n    .asWithPrecursor( (width,height) -\u003e new Widget(width,height) )\n    .check( (width,height,widget) -\u003e widget.size() \u003e width * height ); \n  }\n  ```\n\nWhen this fails it gives us\n\n```\njava.lang.AssertionError: Property falsified after 2 example(s)\nSmallest found falsifying value(s) :-\n{43, 23259, com.example.QuickTheoriesExample$Widget@9e89d68}\nOther found falsifying value(s) :- \n{536238991, 619642140, com.example.QuickTheoriesExample$Widget@59f95c5d}\n{2891501, 215920967, com.example.QuickTheoriesExample$Widget@5ccd43c2}\n{1479099, 47930205, com.example.QuickTheoriesExample$Widget@4aa8f0b4}\n{297099, 11425635, com.example.QuickTheoriesExample$Widget@7960847b}\n{288582, 10972429, com.example.QuickTheoriesExample$Widget@6a6824be}\n{14457, 5650202, com.example.QuickTheoriesExample$Widget@5c8da962}\n{14456, 393098, com.example.QuickTheoriesExample$Widget@512ddf17}\n{14454, 38038, com.example.QuickTheoriesExample$Widget@2c13da15}\n{14453, 38037, com.example.QuickTheoriesExample$Widget@77556fd}\n{14452, 38036, com.example.QuickTheoriesExample$Widget@368239c8}\n \nSeed was 4314310398163\n```\n\nNotice that shrinking works for our custom type without any effort on our part.\n\nDefining the values that make up the valid domain for your objects might not be straightforward and could result in a lot of repeated code between theories.\n\nFortunately the Gen\u003cT\u003e objects that produce the random values can be freely reused and combined with other Gens.\n\ne.g.\n\n```java\n  @Test\n  public void cylindersHavePositiveAreas() {\n    qt()\n    .forAll(cylinders())\n    .check( cylinder -\u003e cylinder.area().compareTo(BigDecimal.ZERO) \u003e 0);\n  }\n  \n  private Gen\u003cCylinder\u003e cylinders() {\n    return radii().zip(heights(),\n        (radius, height) -\u003e new Cylinder(radius, height))\n        .assuming(cylinder -\u003e some sort of validation );\n  }\n\n\n  private Gen\u003cInteger\u003e heights() {\n    return integers().from(79).upToAndIncluding(1004856);\n  }\n\n  private Gen\u003cInteger\u003e radii() {\n    return integers().allPositive();\n  }\n```\n\nGens provide a number of methods that allows them to be mapped to different types or combined with other Gens. All these operations preserve assumptions and allow the resulting types to be shrunk without the need for any additional code.\n\t\n## Profiles\n\nOften its desirable to re-use configurations across multiple properties without duplication and to be\nable to control which configurations are used in different environments. This can be accomplished by \nusing profiles. Profiles are named configurations that are scoped to a given Java class. They can be\nshared across test classes or be local to a JUnit test class. Setting the profile to use is done through\n the `QT_PROFILE` system property. If no profile is set, the default profile is used. \n\nTo define a profile, register it:\n```java\nimport org.quicktheories.core.Profile;\npublic class SomeTests implements WithQuickTheories {\n    static {\n        Profile.registerProfile(SomeTests.class, \"ci\", s -\u003e s.withExamples(10000));\n        Profile.registerProfile(SomeTests.class, \"dev\", s -\u003e s.withExamples(10));\n    }\n}\n``` \n\nFor each class with registered profiles, a default profile can also be registered \n(otherwise the QuickTheories defaults are used). The default profile can also be\nexplicitly selected with `-DQT_PROFILE=default`:\n\n```java\nProfile.registerDefaultProfile(SomeTests.class, s -\u003e s.withExamples(10));\n```\n\n\nProperties must opt-in to using profiles using `withRegisteredProfiles`:\n```java\n@Test\npublic void someProperty() {\n    qt().withRegisteredProfiles(SomeTests.class)\n        .forAll(...)\n        .check(...)\n}\n```\n\nAn explicit profile can also be set:\n```java\n@Test\npublic void someProperty() {\n    qt().withProfile(SomeTests.class, \"ci\")\n        .forAll(...)\n        .check(...)\n}\n```\n\nAny configuration changes made after the call to `withProfile` or `withRegisteredProfiles` will take\nprecedence over values set in the profile. \n\t\n## Modifying the falsification output\n\nValues produces by the sources DSL should provide clear falsification messages.\n\nIf you are working with your own Gens, or would like to modify the defaults, you can supply your own function to be used when describing the falsifying values.\n\nFor example:\n\n```java\n  @Test\n  public void someTestInvolvingCylinders() {\n      qt()\n      .forAll(integers().allPositive().describedAs(r -\u003e \"Radius = \" + r)\n             , integers().allPositive().describedAs(h -\u003e \"Height = \" + h))\n      .check((r,h) -\u003e whatever);\n  }\n```\n\nCustom description functions will be retained when converting to a type with precursors. A description function for the converted type can be optionally passed to the asWithPrecursor function.\n\n```java\n  @Test\n  public void someTestInvolvingCylinders() {\n      qt()\n      .forAll(integers().allPositive().describedAs(r -\u003e \"Radius = \" + r)\n             , integers().allPositive().describedAs(h -\u003e \"Height = \" + h))\n      .asWithPrecursor((r,h) -\u003e new Cylinder(r,h)\n                       , cylinder -\u003e \"Cylinder r =\" + cylinder.radius() + \" h =\" + cylinder.height())        \n      .check((i,j,k) -\u003e whatever);\n  }\n```\n\nA description function can be provided for a type converted without precursors as follows:\n\n```java\n  @Test\n  public void someTestInvolvingCylinders() {\n      qt()\n      .forAll(integers().allPositive().describedAs(r -\u003e \"Radius = \" + r)\n             , integers().allPositive().describesAs(h -\u003e \"Height = \" + h))\n      .as( (r,h) -\u003e new Cylinder(r,h))\n      .describedAs(cylinder -\u003e \"Cylinder r =\" + cylinder.radius() + \" h =\" + cylinder.height())        \n      .check(l -\u003e whatever);\n  }\n```\n\n## Coverage guidance\n\nQuickTheories includes an experimental feature to improve the efficiency of the targeted search. If the coverage jar is included on the classpath QuickTheories will insert probes into the code under test. When these probes reveal that a particular example has exercised new code paths QuickTheories will concentrate the search in this area.\n\nThis approach has been demonstrated to be far more effective at falsifying branched code in simple example cases. It is not yet known how well it performs in real world scenarios.\n\nThere are some disadvantages to coverage guidance. In order to measure coverage QuickTheories must attach an agent to the JVM. The agent will be active from the moment it is installed until the JVM exits - this means it may be active while non QuickTheory tests are running. This will result in an ~10% reduction in performance, and may interfere with JaCoCo and other coverage systems if they are also active. For this reason we recommend running QuickTheories tests in a separate suite if you are using coverage guidance.\n\nCoverage guidance can be disabled on a per test basis.\n\n```java\n  qt() \n  .withGuidance(noGuidance())\n  .etc\n```\n\n## Configuration properties\n\nThree system properties can be set that determine QuickTheories behaviour:\n\n* `QT_SEED` - the random seed to use\n* `QT_EXAMPLES` - the number of examples to try for each theory\n* `QT_SHRINKS` - the number of shrink attempts to make\n\n## Writing good properties\n\nProperties should not just duplicate the logic of your code under test (this is equally true for the example based testing).\n\nInstead properties should try to specify very simple but general invariants that should hold true. Start with very simple general properties and get more specific as\nyou go along.\n\nSome common patterns that produce good properties include :-\n\n(note, these patterns are largely a summary of the material at [fsharpforfunandprofit](http://fsharpforfunandprofit.com/posts/property-based-testing-2/))\n\n### The invariant pattern aka \"Some things never change\"\n\nSome things are expected to remain constant, e.g a map operation should produce the same number of items that it was given, the total balance across two bank accounts should\nremain constant after a transfer etc.\n\t\n### The inverse function pattern aka \"There and back again\"\n\nIf we have two functions that are the inverse of each other then applying the input of one to the other should result in no change.\n\nCommon examples of inverse function pairs include\n\n* serialisation / deserialisation\n* compression / decompression\n* encryption / decryption\n* create / delete\n\n### Analogous function pattern aka \"Different paths same destination\"\t\t\n\nIf you have two functions that implement the same logic, but differ in some other property (perhaps one is inefficient, insecure or implemented in a third party library) then a property can be defined that checks the outputs of the functions match given the same input. \n\n### Idempotence aka \"The more things change, the more they stay the same\"\n\nSometimes it's important/logical that performing an operation multiple times has no effect. e.g if you trim the whitespace from a string multiple times, only the first call to trim should have any observable effect. \n\n## Simple examples\n\nAn example test that is falsifying, showing that adding two positive integers in Java does not always give a positive integer:\n\n```java\n@Test\n  public void addingTwoPositiveIntegersAlwaysGivesAPositiveInteger(){\n    qt()\n    .forAll(integers().allPositive()\n          , integers().allPositive())\n    .check((i,j) -\u003e i + j \u003e 0);  //fails\n  }\n\n```\nAn example of multiple tests for code that claims to find the greatest common divisor between two integers. The first property test fails due to a `java.lang.StackOverflowError` error (caused by attempting to take the absolute value of `Integer.MIN_VALUE`).\n```java\n  @Test\n  public void shouldFindThatAllIntegersHaveGcdOfOneWithOne() {\n    qt().forAll(integers().all()).check(n -\u003e gcd(n, 1) == 1); // fails on\n                                                              // -2147483648\n  }\n\n  @Test\n  public void shouldFindThatAllIntegersInRangeHaveGcdOfOneWithOne() {\n    qt().forAll(integers().between(-Integer.MAX_VALUE, Integer.MAX_VALUE))\n        .check(n -\u003e gcd(n, 1) == 1);\n  }\n\n  @Test\n  public void shouldFindThatAllIntegersHaveGcdThemselvesWithThemselves() {\n    qt().forAll(integers().between(-Integer.MAX_VALUE, Integer.MAX_VALUE))\n        .check(n -\u003e gcd(n, n) == Math.abs(n));\n  }\n\n  @Test\n  public void shouldFindThatGcdOfNAndMEqualsGcdMModNAndN() {\n    qt().forAll(integers().between(-Integer.MAX_VALUE, Integer.MAX_VALUE)\n               ,integers().between(-Integer.MAX_VALUE, Integer.MAX_VALUE))\n        .check((n, m) -\u003e gcd(n, m) == gcd(m % n, n));\n  }\n\n  private int gcd(int n, int m) {\n    if (n == 0) {\n      return Math.abs(m);\n    }\n    if (m == 0) {\n      return Math.abs(n);\n    }\n    if (n \u003c 0) {\n      return gcd(-n, m);\n    }\n    if (m \u003c 0) {\n      return gcd(n, -m);\n    }\n    if (n \u003e m) {\n      return gcd(m, n);\n    }\n    return gcd(m % n, n);\n  }\n```\n\n\n## Design Goals\n\nQuickTheories was written with the following design goals\n\n1. Random by default, but builds must be repeatable \n2. Support for shrinking\n3. Independent of test api (JUnit, TestNG etc)\n\nIt turned out that number 2 was the hard bit as it had many implications for the design. The approach was completely changed between releases in the 0.1x and 0.2x series.\n\nAs of 0.20 shrinking uses an approach similar to the python library hypothesis, whereby shrinking is unaware of the type it is generating. This approach is less flexible than the original approach but allows Gens to be freely composed together while greatly reducing the size of the codebase.\n\n## Background\n\nQuickTheories was produced at [NCR Edinburgh](http://ncredinburgh.com/) as part of our graduate training program. \n\nWe like to do training a little differently – our [new graduates](http://github.com/katyrae) get to work on an interesting project for a weeks with a more worn in and [weathered member of our staff](http://github.com/hcoles). Our motto for these projects is \"software that can fail\" – so we get to play with interesting ideas that may come to nothing. \n\nWe're happy to share the results as open source when we think they're successful.\n\n## Other property based testing systems for Java\n\nIf you don't like QuickTheories you might want to try one of the other systems below which have different design goals. Besides junit-quickcheck, none of them look at implementing shrinking, but all provide ways of generating random values and should work on earlier versions of Java.\n\n* [JUnit-quickcheck](http://pholser.github.io/junit-quickcheck). Tightly integrated with JUnit, uses annotations to configure generators.\n    + As of v0.6 junit-quickcheck also supports shrinking.\n* [JCheck](http://www.jcheck.org/). Tightly integrated with JUnit. Does not look to be maintained.\n* [QuickCheck](https://bitbucket.org/blob79/quickcheck). Not tied to a test framework - provides generators of random values to be used in tests.\n* [FunctionalJava](http://www.functionaljava.org/). Apparently contains a property based testing system, but appears to be completely undocumented.\n* [ScalaCheck](http://www.scalacheck.org/). Mature property based testing system with shrinking, but requires Scala rather than Java. Also seem to be [design level issues with how shrinking works](https://github.com/rickynils/scalacheck/issues/317).\n* [jqwik](http://jqwik.net/). JUnit 5 based implementation using annotations. Supports shrinking.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquicktheories%2Fquicktheories","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquicktheories%2Fquicktheories","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquicktheories%2Fquicktheories/lists"}