属性测试不是写几个例子,而是描述一条对所有输入都成立的规律,让框架去找反例。找到之后怎么收缩成最小的反例?下次怎么复现?边界值怎么混进随机数据?这篇用三个故意写错的函数逐个演示。
|-----------------------jqwik----------------------- tries = 1000 | # of calls to property checks = 1000 | # of not rejected calls generation = RANDOMIZED | parameters are randomly generated after-failure = SAMPLE_FIRST | try previously failed sample, then previous seed when-fixed-seed = ALLOW | fixing the random seed is allowed edge-cases#mode = MIXIN | edge cases are mixed in edge-cases#total = 10 | # of all combined edge cases edge-cases#tried = 10 | # of edge cases tried in current run seed = 7629694908616210214 | random seed to reproduce generated values ├─ jqwik (JUnit Platform) ✔ │ └─ Props ✔ │ └─ reverseTwiceIsIdentity ✔ ├─ JUnit Platform Suite ✔ └─ JUnit Vintage ✔ [ 1 tests found ] [ 1 tests successful ] [ 0 tests failed ]
Property [Props:averageBetween] failed with sample {0=-1, 1=-2147483648}
|-----------------------jqwik-----------------------
tries = 44 | # of calls to property
checks = 44 | # of not rejected calls
generation = RANDOMIZED | parameters are randomly generated
after-failure = SAMPLE_FIRST | try previously failed sample, then previous seed
when-fixed-seed = ALLOW | fixing the random seed is allowed
edge-cases#mode = MIXIN | edge cases are mixed in
edge-cases#total = 81 | # of all combined edge cases
edge-cases#tried = 4 | # of edge cases tried in current run
seed = -1833469337275626533 | random seed to reproduce generated values
Shrunk Sample (12 steps)
arg0: -1
arg1: -2147483648
Original Sample
arg0: -2147483648
arg1: -58912738
├─ jqwik (JUnit Platform) ✔
│ └─ Props ✔
│ └─ averageBetween ✘ Property [Props:averageBetween] failed with sample {0=-1, 1=-2147483648}
├─ JUnit Platform Suite ✔
└─ JUnit Vintage ✔
=> org.opentest4j.AssertionFailedError: Property [Props:averageBetween] failed with sample {0=-1, 1=-2147483648}
[ 1 tests found ]
[ 0 tests successful ]
[ 1 tests failed ]
捕获到的种子: -1833469337275626533 Property [Props:averageBetween] failed with sample {0=-1, 1=-2147483648}
|-----------------------jqwik-----------------------
tries = 1 | # of calls to property
checks = 1 | # of not rejected calls
generation = RANDOMIZED | parameters are randomly generated
after-failure = SAMPLE_FIRST | try previously failed sample, then previous seed
when-fixed-seed = ALLOW | fixing the random seed is allowed
edge-cases#mode = MIXIN | edge cases are mixed in
edge-cases#total = 81 | # of all combined edge cases
edge-cases#tried = 4 | # of edge cases tried in current run
seed = -1833469337275626533 | random seed to reproduce generated values
Sample
arg0: -1
arg1: -2147483648
├─ jqwik (JUnit Platform) ✔
│ └─ Props ✔
│ └─ averageBetween ✘ Property [Props:averageBetween] failed with sample {0=-1, 1=-2147483648}
├─ JUnit Platform Suite ✔
└─ JUnit Vintage ✔
=> org.opentest4j.AssertionFailedError: Property [Props:averageBetween] failed with sample {0=-1, 1=-2147483648}
[ 1 tests found ]
[ 0 tests successful ]
[ 1 tests failed ]
工作目录里 .jqwik-database 是否存在: True ,大小 3078 字节 Property [Props:absNonNegative] failed with sample {0=-2147483648}
|-----------------------jqwik-----------------------
tries = 90 | # of calls to property
checks = 90 | # of not rejected calls
generation = RANDOMIZED | parameters are randomly generated
after-failure = SAMPLE_FIRST | try previously failed sample, then previous seed
when-fixed-seed = ALLOW | fixing the random seed is allowed
edge-cases#mode = MIXIN | edge cases are mixed in
edge-cases#total = 9 | # of all combined edge cases
edge-cases#tried = 5 | # of edge cases tried in current run
seed = 3878513427101564004 | random seed to reproduce generated values
Sample
arg0: -2147483648
├─ jqwik (JUnit Platform) ✔
│ └─ Props ✔
│ └─ absNonNegative ✘ Property [Props:absNonNegative] failed with sample {0=-2147483648}
├─ JUnit Platform Suite ✔
└─ JUnit Vintage ✔
=> org.opentest4j.AssertionFailedError: Property [Props:absNonNegative] failed with sample {0=-2147483648}
[ 1 tests found ]
[ 0 tests successful ]
[ 1 tests failed ] Property [Props:sortKeepsSize] failed with sample {0=[0, 0, 0, 0, 0, 0]}
|-----------------------jqwik-----------------------
tries = 3 | # of calls to property
checks = 3 | # of not rejected calls
generation = RANDOMIZED | parameters are randomly generated
after-failure = SAMPLE_FIRST | try previously failed sample, then previous seed
when-fixed-seed = ALLOW | fixing the random seed is allowed
edge-cases#mode = MIXIN | edge cases are mixed in
edge-cases#total = 5 | # of all combined edge cases
edge-cases#tried = 0 | # of edge cases tried in current run
seed = 4804554757082382072 | random seed to reproduce generated values
Shrunk Sample (8 steps)
arg0: [0, 0, 0, 0, 0, 0]
Original Sample
arg0: [0, 2, 0, 3, 2, 1, 2, 1, 2, 3, 3]
├─ jqwik (JUnit Platform) ✔
│ └─ Props ✔
│ └─ sortKeepsSize ✘ Property [Props:sortKeepsSize] failed with sample {0=[0, 0, 0, 0, 0, 0]}
├─ JUnit Platform Suite ✔
└─ JUnit Vintage ✔
=> org.opentest4j.AssertionFailedError: Property [Props:sortKeepsSize] failed with sample {0=[0, 0, 0, 0, 0, 0]}
[ 1 tests found ]
[ 0 tests successful ]
[ 1 tests failed ] withAssume(int, int)
|-----------------------jqwik-----------------------
tries = 200 | # of calls to property
checks = 195 | # of not rejected calls
generation = RANDOMIZED | parameters are randomly generated
after-failure = SAMPLE_FIRST | try previously failed sample, then previous seed
when-fixed-seed = ALLOW | fixing the random seed is allowed
edge-cases#mode = MIXIN | edge cases are mixed in
edge-cases#total = 81 | # of all combined edge cases
edge-cases#tried = 37 | # of edge cases tried in current run
seed = -3671341646525514134 | random seed to reproduce generated values
├─ jqwik (JUnit Platform) ✔
│ └─ Props ✔
│ └─ withAssume ✔
├─ JUnit Platform Suite ✔
└─ JUnit Vintage ✔
[ 1 tests found ]
[ 1 tests successful ]
[ 0 tests failed ]
stats(int)
timestamp = 2026-10-04T00:34:19.496794, [Props:stats] (100) 范围 =
51-100 (50) : 50 %
11-50 (40) : 40 %
1-10 (10) : 10 %
timestamp = 2026-10-04T00:34:19.497443, [Props:stats] (100) 奇偶 =
奇数 (50) : 50 %
偶数 (50) : 50 %
|-----------------------jqwik-----------------------
tries = 100 | # of calls to property
checks = 100 | # of not rejected calls
generation = EXHAUSTIVE | parameters are exhaustively generated
after-failure = SAMPLE_FIRST | try previously failed sample, then previous seed
when-fixed-seed = ALLOW | fixing the random seed is allowed
edge-cases#mode = MIXIN | edge cases are mixed in
edge-cases#total = 0 | # of all combined edge cases
edge-cases#tried = 0 | # of edge cases tried in current run
seed = 8106488218275411 | random seed to reproduce generated values
├─ jqwik (JUnit Platform) ✔
│ └─ Props ✔
│ └─ stats ✔
├─ JUnit Platform Suite ✔
└─ JUnit Vintage ✔
[ 1 tests found ]
[ 1 tests successful ]
[ 0 tests failed ]
generated(int, java.lang.String)
arg0: 2
arg1: "N"
arg0: 0
arg1: ""
arg0: 8
arg1: "a"
arg0: 9
arg1: "A"
arg0: 4
arg1: "WMl"
arg0: 1
arg1: "iAT"
arg0: 1
arg1: "z"
arg0: 0
arg1: "A"
arg0: 4
arg1: "z"
arg0: 7
arg1: ""
arg0: 0
arg1: "Z"
arg0: 9
arg1: "al"
arg0: 7
arg1: ""
arg0: 8
arg1: "YK"
arg0: 5
arg1: "PxI"
arg0: 3
arg1: "vp"
arg0: 2
arg1: "f"
arg0: 0
arg1: "a"
arg0: 5
arg1: "Z"
arg0: 6
arg1: ""
|-----------------------jqwik-----------------------
tries = 20 | # of calls to property
checks = 20 | # of not rejected calls
generation = RANDOMIZED | parameters are randomly generated
after-failure = SAMPLE_FIRST | try previously failed sample, then previous seed
when-fixed-seed = ALLOW | fixing the random seed is allowed
edge-cases#mode = MIXIN | edge cases are mixed in
edge-cases#total = 20 | # of all combined edge cases
edge-cases#tried = 3 | # of edge cases tried in current run
seed = 505804894492505318 | random seed to reproduce generated values
├─ jqwik (JUnit Platform) ✔
│ └─ Props ✔
│ └─ generated ✔
├─ JUnit Platform Suite ✔
└─ JUnit Vintage ✔
[ 1 tests found ]
[ 1 tests successful ]
[ 0 tests failed ]