1

生成式测试似乎很有趣,但我需要生成随机 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 函数?

4

2 回答 2

3

需要两个 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"]}}

这显示了您可以从测试用例中消除多少噪声。

于 2015-01-30T23:11:33.743 回答
2

在 test.check 版本0.9.0中,有一个内置程序gen/uuid可以生成不收缩的随机 uuid 。

如果你真的想要缩小 UUID,那么 generate-two-longs 方法也更容易,因为新方法gen/large-integer将生成完整的 long 范围,尽管不是均匀分布。

仍然没有内置的生成器可以在所有long 上生成均匀分布,但我认为这是将来应该添加的东西。

于 2015-12-29T01:08:54.057 回答