So, chance, huh? Randomness.
I'm looking into how I can test a class whose sole responsibility is to return weighted random results, that is, where there is a set probability of returning true.
The trouble is, random being what it is, sometimes the result doesn't reflect the initial probability.
Here's my attempt, which passes the specs most of the time.
chance.rb
class Chance
include Singleton
def self.percent(amount)
(rand(100) + 1) <= amount
end
# x in y chance of being true
def self.proportion(x, y)
rand(y) <= x
end
end
chance_spec.rb
describe Chance do
context 'percent' do
it 'should return true 50% of the time' do
results = 100.times.collect{ Chance.percent(50) }
results.select{|x|x}.count.should be_within(10).of(50)
end
it 'should return true 75% of the time' do
results = 100.times.collect{ Chance.percent(75) }
results.select{|x|x}.count.should be_within(10).of(75)
end
it 'should return true 25% of the time' do
results = 100.times.collect{ Chance.percent(25) }
results.select{|x|x}.count.should be_within(10).of(25)
end
it 'should return true 100% of the time' do
results = 100.times.collect{ Chance.percent(100) }
results.select{|x|x}.count.should eq(100)
end
it 'should return true 0% of the time' do
results = 100.times.collect{ Chance.percent(0) }
results.select{|x|x}.count.should eq(0)
end
end
context 'proportion' do
it 'should return true 6 in 12 times' do
results = 12.times.collect{ Chance.proportion(6, 12) }
results.select{|x|x}.count.should be_within(2).of(6)
end
it 'should return true 2 in 6 times' do
results = 6.times.collect{ Chance.proportion(2, 6) }
results.select{|x|x}.count.should be_within(1).of(2)
end
end
end
Any clues?