В настоящее время я работаю над реализацией интересных структур данных в 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
Одна из проблем, связанных с фильтром Блума, заключается в том, что он имеет возможность возвращать ложные срабатывания, ложно возвращая истину для включения элементов, которые никогда не вставлялись в фильтр.
Иногда фильтр ведет себя так, что его легко проверить:
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)
Итак, внезапно у нас есть строка «ложное срабатывание», обеспечивающая ... ложное срабатывание. Мой вопрос: как мы можем это проверить?
Если мы выберем значения, которые просто произойдут для работы с нашими тестами, тогда я
чувствую, что тесты становятся слишком хрупкими. Например, если мы изменим
функция хеширования, то мы все еще можем иметь совершенно правильный Блум
Фильтр, который начинает проваливать некоторые тесты из-за значений, которые мы выбрали
проверить оригинальную реализацию.
Моей второй мыслью было проверить, что фильтр ведет себя ожидаемым образом.
кстати, просто проверяя, что мы получаем примерно ожидаемое число
ложный
позитивы
из него, варьируя количество хэш-функций и размер
внутренний буфер. Хотя этот подход может проверить общую грубость
Правильность фильтра волнуюсь, что он не сможет отловить
ошибки, которые приводят к тому, что он сообщает неверные значения для отдельных случаев (например, ложные
негативы).
Я слишком пессимистично оцениваю эффективность двух методов тестирования, описанных выше, или мне не хватает способа протестировать классы, такие как фильтр Блума, результаты которого непредсказуемы?