[rspec-users] Questions about testing a module method that randomly creates stuff from list.

Greg Ditrick gditrick at fuse.net
Fri Jul 16 12:38:28 EDT 2010


---- David Chelimsky <dchelimsky at gmail.com> wrote: 
> On Jul 15, 2010, at 12:18 PM, Greg Ditrick wrote:
> 
> 
> This sounds like a long, procedural method. Can it be broken down any further (i.e. delegating more of its work to other methods)?

Yes, it is.  The sub methods are the broken down part and not overridden super methods like I guess I made it sound based on your answers below.
 

> 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.

Well, they don't assign instance variables.  They are really just methods handling conditions of the randomness in the parent method.


> 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?

Funny you used die when this problem is for a game.

Yes, I can stub out the conditions that each child method handles.  This procedural method has grown because of the permutations increase exponentially with more data.  But, the conditions to handle (defined in the child methods) have become finite and all I have to do is test those with mocks and stubs.

I know I put the cart before the horse in TDD/BDD, but this was a very difficult problem to solve:
Create a random tournament layout of unique teams of players where a team is matched with another random team of different players and every player plays on teams made up of all the other players to complete the tournament.  This way you find the best individual player.  Example of this would be euchre, bridge, other team playing card games, etc.  But not limited to card games and not limited to 2 man teams.   Also, it must allow for uneven number of players in the tournament. i.e. players would have byes throughout the tournament and those byes would be evenly distributed throughout the tournament.  For example: a tournament of 2 players per team and 2 teams per match made up of say 15 players would have all players have had the same number of byes at the end of every 5th round.

I actually wrote this 20 years ago in ANSI C.  Now I have written it in ruby.  It has been just about as hard to do, but less lines of code, cleaner and runs faster mainly because in the C code evaluated each team as it was searching for a team to place into a round where is the ruby code it was simple to remove and shrink the possible opponents with one line of code.  :)  So, while the C code would take maybe hours to figure out a layout of 200+ euchre players.  The ruby code does it in a few minutes on the same machine.  Not that you would every have that large of a tournament.  Just out of curiosity, I tried the a very large size tournament to compare the timing.

I do have one more question, how would you write a test for a recursive method?  I have a couple of those too.

Thanks for the ideas,

GregD


More information about the rspec-users mailing list