-
Notifications
You must be signed in to change notification settings - Fork 641
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
PropertyTesting used to work, no longer does #58
Comments
I can confirm the PropertyTesting version generates four tests which pass with 1.2. This is actually a very good behaviour that seems may have been lost. |
And: class Factorial_KotlinTest_PropertyBased : StringSpec() {
init {
val algorithms = listOf(
"iterative" to {x:Int -> iterative(x)},
"reductive" to {x:Int -> reductive(x)},
"naïve_recursive" to {x:Int -> naïve_recursive(x)},
"tail_recursive" to {x:Int -> tail_recursive(x)}
)
forAll(algorithms) { a ->
val f = a.second
a.first + ":recurrence relation is true for all non-negative integer values" {
forAll { i: Int ->
if (0 < i && i < 500) { f(i) == (i.bigint * f(i - 1)) }
else { true }
}
}
}
}
} generates the error:
|
Do you have the implementation for iterative and reductive |
It's from my Factorial Git repository on GitHub, https://github.com/russel/Factorial/tree/master/Kotlin I can post the code here if that is better. |
Ok thanks. So the test "description" must be top level, and then the for all nested inside. class Factorial_KotlinTest_PropertyBased : StringSpec() {
init {
val algorithms = listOf(
"iterative" to { x: Int -> iterative(x) },
"reductive" to { x: Int -> reductive(x) },
"naïve_recursive" to { x: Int -> naïve_recursive(x) },
"tail_recursive" to { x: Int -> tail_recursive(x) }
)
":recurrence relation is true for all non-negative integer values" {
forAll(algorithms) { a ->
val f = a.second
a.first +
forAll { i: Int ->
if (0 < i && i < 500) {
f(i) == (i.bigint * f(i - 1))
} else {
true
}
}
}
}
}
} |
This is nowhere near as good from the perspective of reporting. The 1.2 version allowed for construction of test cases table style with the tests being property style. This is a great model since it is "unrolling" over the deterministic variable but leaving the random stuff "hidden". This way of working is available in QuickCheck and Hypothesis, because it is the right thing to do. KotlinTest 1.2 followed this model. Now with 1.3 we have given up that way of working and are now constrained in a way that seems unnecessary: the test cases are not actually top level it is just that the ability to table drive the creation of the test cases has been removed. For now I'll stick with 1.2. |
So you just want to create the tests themselves programatically. The outer forAll is a test matcher which should only be used in a test proper, I'm surprised it worked before. You can do what you want with standard forEach and I think it's actually a bit more readable while doing what you want (I think). Try: class Factorial_KotlinTest_PropertyBased : StringSpec() {
init {
val algorithms = listOf(
"iterative" to { x: Int -> iterative(x) },
"reductive" to { x: Int -> reductive(x) },
"naïve_recursive" to { x: Int -> naïve_recursive(x) },
"tail_recursive" to { x: Int -> tail_recursive(x) }
)
algorithms.forEach {
val f = it.second
(it.first + ":recurrence relation is true for all non-negative integer values") {
forAll { i: Int ->
if (0 < i && i < 500) {
f(i) == (i.bigint * f(i - 1))
} else {
true
}
}
}
}
}
} |
This looks spot on. I was being blinkered by the previous working version. I am upgrading now. Note to self: work harder at this. |
No that's fine, the previous property testing was undocumented so wasn't clear what it was I was intending. |
I notice you're using a filter of sorts (the if statement and else with true) so what we need to add in is the equivalent of ScalaCheck's forAll { i: Int ->
when (0 < i && i < 500) {
f(i) == (i.bigint * f(i - 1))
}
} We need another keyword than |
Something like this, the underlying need anyway. Some frameworks say do not filter the standard generator (since this may mean selecting 200 values to get 100 useful one) but do away with the default generator and introduce a specific one which generates in the right range. Specks has this for Ceylon for example. It uses the names parameters technology to do this. |
I suppose that makes sense. Perhaps either way would be handy. We can always add Gen.nonNegInt etc. |
That route is how Frege has gone for conditioning things, pointfree function composition helps for using that technique though. As long as the forAll/when results in 100 (or whatever the number is at the time) tests applied no matter how big the sample has to be to achieve it, then that is what matters most. |
@sksamuel The forAll/when combination above doesn't work on latest release Kotlin/KotlinTest (1.0.5) the forAll gives a type inference fail. (name + ": recurrence relation is true for all non-negative integer values") {
forAll{i: Int ->
when (0 < i && i < 500) { f(i) == (i.bigint * f(i - 1)) }
}
} results in:
whereas using an if statement works fine. |
@russel I think it would be best to file a new issue for this. |
The test:
was working fine 10 days ago. With the 1.3.1 release I thought I'd update. I thought:
to be the replacement. However it is clearly broken since it passes and clearly should not. There is an error introduced which means it should fail.
The text was updated successfully, but these errors were encountered: