How do I test (TDD) a singleton class?

2019-07-16 06:39发布

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!

2条回答
霸刀☆藐视天下
2楼-- · 2019-07-16 07:04

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
查看更多
干净又极端
3楼-- · 2019-07-16 07:11

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

查看更多
登录 后发表回答