Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Constraint Documentation #163

Open
aaron868 opened this issue Jun 15, 2017 · 9 comments
Open

Improve Constraint Documentation #163

aaron868 opened this issue Jun 15, 2017 · 9 comments

Comments

@aaron868
Copy link

Nice library. I've been experimenting with different tests but cannot find documentation about the possible constraints. For example, how do you constrain a String to length 1? Could you please add documentation (along with examples) on the constraints for each of the supported basic types?

Thanks.

@pholser
Copy link
Owner

pholser commented Jul 20, 2017

@aaron868 Thanks for your interest in junit-quickcheck! Sorry for the late reply.

It's up to individual generators to decide when configuration annotations to admit. You can find these as methods with signature configure(A), where A is an annotation type that is itself marked as GeneratorConfiguration. This tells more about configuration annotations.

@When(satisfies = expr) is another way to constrain generated values. This may help.

For purposes of resolving this issue -- what form would you imagine the additional documentation to take?

@aaron868
Copy link
Author

The construct @when(satisfies = expr) would work. I don't see, however, a reference guide for constraint expressions. The link you provided (http://pholser.github.io/junit-quickcheck/site/0.7/usage/constraining.html) does not provide one. I assume that the constraints allowed are the OGNL operators. Could you add a few more examples of using them in the this library?

@pholser
Copy link
Owner

pholser commented Jul 23, 2017

@aaron868 Sure thing. Any OGNL expression that evaluates to boolean is allowed. #_ is taken to be the annotated parameter.

I'll add a couple more examples of the usage of @When(satisfies = ...). Thanks again for the feedback!

@bjordan2010
Copy link

bjordan2010 commented Sep 1, 2020

This ocde is a variation on the documentation. Why does this test fail?

@Property(trials = 5)
public void when(@When(satisfies = "#_ > 1000 && #_ < 100000") int num)
{
    System.out.println("When: " + num);
    assertTrue(num > 0);
}

I get:

com.pholser.junit.quickcheck.internal.generator.PropertyParameterGenerationContext$DiscardRatioExceededException: For parameter [junitquickcheck.QuickCheck.when:arg0] with discard ratio [10], 11 unsuccessful values and 0 successes. Stopping.
at com.pholser.junit.quickcheck.internal.generator.PropertyParameterGenerationContext.evaluate(PropertyParameterGenerationContext.java:105)
at com.pholser.junit.quickcheck.internal.generator.PropertyParameterGenerationContext.generate(PropertyParameterGenerationContext.java:83)
at com.pholser.junit.quickcheck.internal.SeededValue.(SeededValue.java:37)

But if I change it to:

 @Property(trials = 5)
public void when(@When(satisfies = "#_ > 1000") int num)
{
    System.out.println("When: " + num);
    assertTrue(num > 0);
}

Then it works. It seems to me like the && is not doing an AND but an OR in the satisfies clause but perhaps I am missing something about how @when works.

@pholser
Copy link
Owner

pholser commented Sep 1, 2020

@bjordan2010 Thanks for this ... will investigate.

@pholser
Copy link
Owner

pholser commented Sep 1, 2020

@bjordan2010 I should mention also that if you want to guarantee that the generated values fall within the range you want, you can mark the parameter with @InRange:

    @Property public void inRange(@InRange(min = 1001, max = 9999) int i) {
        // ...
    }

@pholser
Copy link
Owner

pholser commented Sep 2, 2020

@bjordan2010

@When(satisfies = "#_ > 1000 && #_ < 100000") int i will have junit-quickcheck generate a random int, then subject it to the "when" expression...if it matches, junit-quickcheck verifies the property, and if not, junit-quickcheck discards the value and tries again. If the ratio of discards to matches ever exceeds a certain ratio (10 by default), junit-quickcheck gives up. So @When(satisfies) is sort of a low-fidelity constraint on generation.

When the expr is 1000 < x < 100000, I suspect that very few values actually match; the default generation for integers can be anywhere from MIN_VALUE to MAX_VALUE, so the odds of getting enough hits before you exceed the discard ratio is small. When the expr is x < 1000, you stand a better chance of getting enough hits before that ratio is exceeded.

As noted above, your better bet is to use the @InRange annotation on the property parameter. All the numeric generators in junit-quickcheck-generators support this constraint.

@bjordan2010
Copy link

@pholser

Then the example of @when in the documentation 0 <= x <= 9 is also likely to fail since it alludes to looking for "Single Digits" for an integer correct? It makes it seem like those are the only values that will be generated but that is not the case.
That would require a custom generator. A test that will pass for an integer is one that is using @when for -2147483648 <= x <= 2147483647 since that satisfies clause would include all values of an integer. I hope I am understanding the @when clause correctly now.

@pholser
Copy link
Owner

pholser commented Sep 2, 2020

@bjordan2010 Correct. I wonder if @Assuming would be a more evocative name for @When ... it kind of behaves like JUnit assumptions, with the idea of trying values until trials is met or there are too many non-matches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants