Questions about testing a module method that randomly creates stuff from list

All,

I have a method in a shared Module that shuffles data and then output
other data. The method is somewhat large (maybe 50 lines) and
sometimes calls other sub methods to help to complete the output which
must meet a specific criteria or it re-shuffles.

My questions are:

  1. How do I capture that a sub method is called?
    Module.should_recieve(:sub_method) ???
  2. How do I capture the rand number that caused a condition (like the
    :sub_method being called, an Error raised, etc.). I know srand will
    give me the seed that caused it. But, how do I capture it on the
    failure? For example:
    true.should_not be_true || File.open(“capture_rand.out”,”a”) { |f|
    f.puts “#{srand}”}
    Can you do an || (or) statement like that and have it capture the seed
    and fail the example? Any ideas? Any other ways of capturing data like
    that?

After I capture the seeds, I’m thinking I could than use those seeds to
fine tune specific tests.

Thanks,

GregD

On Jul 15, 2010, at 12:18 PM, Greg D. wrote:

All,

I have a method in a shared Module that shuffles data and then output other data. The method is somewhat large (maybe 50 lines) and sometimes calls other sub methods to help to complete the output which must meet a specific criteria or it re-shuffles.

This sounds like a long, procedural method. Can it be broken down any
further (i.e. delegating more of its work to other methods)?

My questions are:

I’ll try to answer them, but I don’t have much to go on. If you want
more specific answers, we’ll need to see the method in question.

  1. How do I capture that a sub method is called? Module.should_recieve(:sub_method) ???

I try to avoid message expectations on the same object that I’m
spec’ing. That said, here’s how you can do it:

object = Object.new.extend(MySharedModule)

object.should_receive(:sub_method)
object.super_method

The problem with this approach, especially in light of what sounds like
a very complex method, is that the real sub_method is not called, so you
have to set up the proper return value:

object.should_receive(:sub_method).and_return(:a_value_that_super_method_can_work_with)
object.super_method

If the real sub_method sets any internal state (i.e. assigns values to
instance variables), then this won’t work at all.

  1. How do I capture the rand number that caused a condition (like the :sub_method being called, an Error raised, etc.). I know srand will give me the seed that caused it. But, how do I capture it on the failure? For example:
    true.should_not be_true || File.open(“capture_rand.out”,”a”) { |f| f.puts “#{srand}”}
    Can you do an || (or) statement like that and have it capture the seed and fail the example? Any ideas? Any other ways of capturing data like that?

It’s much easier to control state in an example, rather than inspect
state and set different expectations based on it. Consider a simulation
of a game that involves a die:

die = double(‘die’)
die.stub(:roll).and_return(2)

board.set(piece).at(30)
board.roll(die)
board.square_at(32).should contain(piece)

Make sense?

HTH,
David