测试不可预测的功能

时间:2011-12-20 00:02:42

标签: testing probability bloom-filter

我目前正在搞乱在Ruby中实现有趣的数据结构,并且在测试没有可预测输出的函数方面遇到了问题。我目前正致力于Bloom Filter我已将完整性包含在下面的实施中:

require "zlib"

class BloomFilter
  def initialize(size=100, hash_count=3)
    raise(ArgumentError, "negative or zero buffer size") if size <= 0
    raise(ArgumentError, "negative or zero hash count") if hash_count <= 0

    @size = size
    @hash_count = hash_count
    @buffer = Array.new(size, false)
  end

  def insert(element)
    hash(element).each { |i| @buffer[i] = true}
  end

  def maybe_include?(element)
    hash(element).map { |i| @buffer[i] }.inject(:&)
  end

  private :hash
  def hash(element)
    hashes = []

    1.upto(@hash_count) do |i|
      hashes << Zlib.crc32(element, i)
    end

    hashes.map { |h| h % @size }
  end
end

布隆过滤器的一个问题是它有可能通过错误地返回true来包含从未插入过滤器的元素,从而返回误报。

有时,过滤器的行为方式很容易测试:

b = BloomFilter.new(50, 5)

b.insert("hello")
puts b.maybe_include?("hello") # => true
puts b.maybe_include?("goodbye") # => false

然而,它有时会破坏趋势,并以不可预测的方式行事。 (我已经减少了缓冲区的大小,以便快速找到冲突。)

b = BloomFilter.new(5, 4)

b.insert("testing")
puts b.maybe_include?("testing") # => true
puts b.maybe_include?("not present") # => false
puts b.maybe_include?("false positive") # => true (oops)

所以突然间我们有了字符串&#34;误报&#34;提供......误报。我的问题是我们如何测试这个?

  • 如果我们选择刚刚发生的值来处理我们的测试,那么我 感觉测试变得太脆弱了。例如,如果我们改变 哈希函数然后我们可能仍然有一个完全正确的布卢姆 由于我们选择的值,过滤器开始失败某些测试 测试原始实现。

  • 我的第二个想法是测试过滤器的行为是否符合预期 通过检查我们大致得到expected number of false positives的方式 通过改变散列函数的数量和大小 内部缓冲区。虽然这种方法可能会测试整体粗糙度 过滤器的正确性我担心它无法捕获 导致它报告个别情况的错误值的错误(例如false 底片)。

我对上面测试它的两种方法的有效性过于悲观,还是我错过了测试输出不可预测的Bloom Filter等类的方法?

3 个答案:

答案 0 :(得分:2)

你选择刚刚发生工作的价值是对的,这是一个坏主意。但是,你的第二个想法并不是那么糟糕。

您应该始终能够测试应该在bloom过滤器中的值是否存在。您可以随机生成许多字符串,并检查阈值数量是否为误报。这样,如果您更改散列函数,您的单元测试仍然可以工作,并且仍会报告过滤器具有可接受的误报率。

答案 1 :(得分:0)

测试是关于确认您的期望。如果你不能自己解释Bloom过滤器会返回什么(考虑到你提到的脆弱性),你不能期望有这样的期望。 (我发誓,我并不想制造双关语:P)

我的第一个直觉是在所有有趣的哈希算法上确认N个生成输入的误报率。这样可以自动实现您手动执行这些测试的安全性。

为实现这一目标,我建议您将测试代码考虑在内,以便表达如下简单:

&LT;警告&GT;未验证的代码&lt; / warning&gt;

class BloomFilterTestCase << TestCase
  def bloom_incidence(alg, pop, false_positives)
    define_method("test_bloom_incidence_${alg}_${pop}_${false_positives}") do  
      # code code code
    end
  end

  bloom_incidence :naive, 50, 0.05
end

答案 2 :(得分:-1)

  

布隆过滤器是一种节省空间的概率数据结构,用于测试元素是否是集合的成员。假阳性是可能的,但假阴性不是。

仅仅从Bloom过滤器的描述来看,应该很清楚,测试误报是没有意义的。它本身是未定义的,正面测试的结果是什么,所以你无法对期望某个结果的它进行测试。您可以保证并因此测试的唯一事项是:

  • 该函数返回一个布尔值
  • 该函数不会抛出任何错误
  • 没有漏报