如何生成可以在 Clojure 中使用 test.check 的 UUID
How to generate UUIDs that can work with test.check in Clojure
生成测试似乎很有趣,但我需要生成随机 UUID 作为测试的一部分。 java.util.UUID/newRandom 不适合 test.check 收缩。
java 代码如下所示:
public static UUID randomUUID()
{
long lsb = r.nextLong();
long msb = r.nextLong();
lsb &= 0x3FFFFFFFFFFFFFFFL;
lsb |= 0x8000000000000000L; // set top two bits to variant 2
msb &= 0xFFFFFFFFFFFF0FFFL;
msb |= 0x4000; // Version 4;
return new UUID( msb, lsb );
}
翻译成 Clojure 比看起来更棘手。
如何在Clojure中编写一个可以成功收缩的随机UUID函数?
采用两个 long 并生成正确的类型 4 UUID 的 fn 是:
(defn make-uuid [[msb lsb]]
(java.util.UUID. (-> msb
(bit-clear 15)
(bit-set 14)
(bit-clear 13)
(bit-clear 12))
(-> lsb
(bit-set 63)
(bit-clear 62))))
您可以使用正则表达式检查结果,(需要先将其转换为字符串)。
(def uuid-v4-regex
#"(?i)[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[98ab][a-f0-9]{3}-[a-f0-9]{12}")
然后你可以按如下方式测试:
(def uuids (gen/fmap make-uuid (gen/tuple (gen/choose 0 Long/MAX_VALUE)
(gen/choose 0 Long/MAX_VALUE))))
(defspec check-random-uuid 100000
(for-all [uuid uuids]
(re-find uuid-v4-regex (str uuid))))
测试如下:
(check-random-uuid)
=> {:result true, :num-tests 100000, :seed 1422050154338}
为了好玩,我删除了第二个字段的一个有效字符 (9),这就是失败测试的样子,因此您可以看到从 :fail 缩小到 :smallest 有何帮助。
(pp/pprint (check-random-uuid))
{:result nil,
:seed 1422050276824,
:failing-size 2,
:num-tests 3,
:fail [#uuid "2c6d1442-eec3-4800-972e-02905c1b3c00"],
:shrunk
{:total-nodes-visited 932,
:depth 29,
:result nil,
:smallest [#uuid "00000000-0000-4000-9000-000000000000"]}}
这表明可以从测试用例中去除多少噪声。
从 test.check 版本 0.9.0
开始,有一个 built-in gen/uuid
生成 不收缩 的随机 uuid .
如果你真的想要缩小 UUID,generate-two-longs 方法也更容易,因为新的 gen/large-integer
将生成全范围的多头,虽然不是均匀分布。
仍然没有内置生成器可以在 所有 多头上生成均匀分布,但我认为这是将来应该添加的东西。
生成测试似乎很有趣,但我需要生成随机 UUID 作为测试的一部分。 java.util.UUID/newRandom 不适合 test.check 收缩。
java 代码如下所示:
public static UUID randomUUID()
{
long lsb = r.nextLong();
long msb = r.nextLong();
lsb &= 0x3FFFFFFFFFFFFFFFL;
lsb |= 0x8000000000000000L; // set top two bits to variant 2
msb &= 0xFFFFFFFFFFFF0FFFL;
msb |= 0x4000; // Version 4;
return new UUID( msb, lsb );
}
翻译成 Clojure 比看起来更棘手。
如何在Clojure中编写一个可以成功收缩的随机UUID函数?
采用两个 long 并生成正确的类型 4 UUID 的 fn 是:
(defn make-uuid [[msb lsb]]
(java.util.UUID. (-> msb
(bit-clear 15)
(bit-set 14)
(bit-clear 13)
(bit-clear 12))
(-> lsb
(bit-set 63)
(bit-clear 62))))
您可以使用正则表达式检查结果,(需要先将其转换为字符串)。
(def uuid-v4-regex
#"(?i)[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[98ab][a-f0-9]{3}-[a-f0-9]{12}")
然后你可以按如下方式测试:
(def uuids (gen/fmap make-uuid (gen/tuple (gen/choose 0 Long/MAX_VALUE)
(gen/choose 0 Long/MAX_VALUE))))
(defspec check-random-uuid 100000
(for-all [uuid uuids]
(re-find uuid-v4-regex (str uuid))))
测试如下:
(check-random-uuid)
=> {:result true, :num-tests 100000, :seed 1422050154338}
为了好玩,我删除了第二个字段的一个有效字符 (9),这就是失败测试的样子,因此您可以看到从 :fail 缩小到 :smallest 有何帮助。
(pp/pprint (check-random-uuid))
{:result nil,
:seed 1422050276824,
:failing-size 2,
:num-tests 3,
:fail [#uuid "2c6d1442-eec3-4800-972e-02905c1b3c00"],
:shrunk
{:total-nodes-visited 932,
:depth 29,
:result nil,
:smallest [#uuid "00000000-0000-4000-9000-000000000000"]}}
这表明可以从测试用例中去除多少噪声。
从 test.check 版本 0.9.0
开始,有一个 built-in gen/uuid
生成 不收缩 的随机 uuid .
如果你真的想要缩小 UUID,generate-two-longs 方法也更容易,因为新的 gen/large-integer
将生成全范围的多头,虽然不是均匀分布。
仍然没有内置生成器可以在 所有 多头上生成均匀分布,但我认为这是将来应该添加的东西。