I am learning Ruby with TDD using Mocha and MiniTest. I have a class that has one public method and many private methods, so the only method my tests are going to tests are the public one.
This public method does some processing and creates an array which is sent to another object:
def generate_pairs()
# prepare things
pairs = calculate_pairs()
OutputGenerator.write_to_file(path, pairs)
end
Great. To test it, I would like to mock the OutputGenerator.write_to_file(path, pairs)
method and verify the parameters. My first test I could sucessfully implement:
def test_find_pair_for_participant_empty_participant
available_participants = []
OutputGenerator.expects(:write_to_file).once.with('pairs.csv', [])
InputParser.stubs(:parse).once.returns(available_participants)
pair = @pairGenerator.generate_pairs
end
Now I would like to test with one pair of participants. I am trying this
def test_find_pair_for_participant_only_one_pair
participant = Object.new
participant.stubs(:name).returns("Participant")
participant.stubs(:dept).returns("D1")
participant_one = Object.new
participant_one.stubs(:name).returns("P2")
participant_one.stubs(:dept).returns("D2")
available_participants = [participant_one]
OutputGenerator.expects(:write_to_file).once.with('pairs.csv', equals([Pair.new(participant, participant_one)])) # here it fails, of course
InputParser.stubs(:parse).once.returns(available_participants)
@obj.stubs(:get_random_participant).returns(participant)
pair = @obj.generate_pairs
end
The problem is that equals will only match the obj reference, not the content.
Is there any way I can verify the content of the array? Verifying the number of elements inside the array would also be extremely useful.
ps: I am sorry if the code doesn't follow ruby standards, I am doing this project to learn the language.
What you are testing here demonstrates a kind of hard coupling. That is your primary class is always dependent on
OutputGenerator
which makes testing your outputs tricky and can lead to a lot of pain if/when you have to refactor your designs.A good pattern for this is dependency injection. With this you can just write a temporary ruby object you can use to evalute the output of your function however you want:
Hope this helps! Dependency Injection is not always appropriate but it is great for cases like this.
Some other posts about the use of dependency injection you might find helpful: