4

I am starting with DDD and TDD in a Ruby application using Minitest. I created a repository class (no database access, but it generates the entities for me). It is a singleton.

I would like to test the generation of the entities. The problem is that because it is a singleton, the order of executions of the tests affect the results.

Is there any way to force the disposal of the singleton element so it is "fresh"?

Here is my repository code:

require "singleton"

class ParticipantRepository
    include Singleton

    def initialize()
        @name_count = 0
    end

    def generate_participant()
        participant = Participant.new
        participant.name = "Employee#{get_name_count()}"
        return participant
    end

    private 
    def get_name_count()
        old_name_count = @name_count
        @name_count += 1
        return old_name_count
    end
end

And the tests:

require_relative 'test_helper'


class ParticipantRepositoryTest < MiniTest::Unit::TestCase

    def setup()
        @repository = ParticipantRepository.instance
    end

    def test_retrieve_participant
       participant = @repository.generate_participant

       refute_nil participant
       refute_nil participant.name
       refute_equal("", participant.name)
       assert_equal(0, participant.subordinates_count)
    end

    def test_employee_name_increment
        participant1 = @repository.generate_participant
        participant2 = @repository.generate_participant

        refute_equal(participant1.name, participant2.name)

        index_participant1 = /Employee([0-9]+)/.match(participant1.name)[1]
        index_participant2 = /Employee([0-9]+)/.match(participant2.name)[1]

        assert_equal(0, index_participant1.to_i)
        assert_equal(1, index_participant2.to_i)
    end

end

The assertion assert_equal(0, index_participant1.to_i) succeeds when test_employee_name_increment is executed first and fails if it is executed last.

I would like to be able to test the repository (because it will evolve into something bigger). How can I do that?

Thanks!

JSBach
  • 4,679
  • 8
  • 51
  • 98
  • Singletons and testability are often at odds. Consider using DI of some sort to enforce the singleton-ness instead of having the class worry about that. – Matt Ball Oct 02 '14 at 23:10
  • @MattBall this would be great. Would you have any references to how to use DI to solve this? – JSBach Oct 02 '14 at 23:54
  • Nothing specific; I don't write Ruby. Take a look: http://stackoverflow.com/search?q=ruby+dependency+injection – Matt Ball Oct 03 '14 at 01:15
  • Take a look at my answer to a similar question - http://stackoverflow.com/a/23901644/633234 – Cameron Martin Feb 19 '15 at 15:43

2 Answers2

5

Ordering your tests won't matter. To properly test a singleton class you need to treat it like an instance object. To do that, wrap your singleton in an anonymous Class during setup. Every time setup is called you'll get an untouched copy of the ParticipantRepository:

def setup
  @repository = Class.new(ParticipantRepository).instance
end
  • 1
    There are a few other options (and I think @MicahJaffe's answer is among them) listed here: http://stackoverflow.com/a/12128594/3367343. I do like this one though. – Travis Hohl Oct 03 '14 at 18:47
3

Call i_suck_and_my_tests_are_order_dependent!() at the top of your tests when you absolutely positively need to have ordered tests. In doing so, you’re admitting that you suck and your tests are weak.

...I promise I didn't write this method or the docs.

For more info, see: http://www.ruby-doc.org/stdlib-2.0/libdoc/minitest/rdoc/MiniTest/Unit/TestCase.html#method-c-i_suck_and_my_tests_are_order_dependent-21

Travis Hohl
  • 2,176
  • 2
  • 14
  • 15
  • wow, that is an unexpected method name :p I will try to change my architecture in order to avoid using this one. Any ideas – JSBach Oct 02 '14 at 23:51
  • by the way, the tests are not order dependent themselves. The problem is that I expect to have a given value but the instance used is not "fresh" because it is a singleton. Solving the singleton problem solves the order dependency problem – JSBach Oct 03 '14 at 00:03