Я использую RSpec и хочу проверить конструктор класса Singleton более одного раза.
Как я могу это сделать?
С наилучшими пожеланиями
Я использую RSpec и хочу проверить конструктор класса Singleton более одного раза.
Как я могу это сделать?
С наилучшими пожеланиями
посмотрите http://blog.ardes.com/2006/12/11/testing-singletons-with-ruby:
require 'singleton'
class <<Singleton
def included_with_reset(klass)
included_without_reset(klass)
class <<klass
def reset_instance
Singleton.send :__init__, self
self
end
end
end
alias_method :included_without_reset, :included
alias_method :included, :included_with_reset
end
Одиночные классы по существу делают это
def self.instance
@instance ||= new
end
private_class_method :new
Итак, вы можете обойти memoization вообще, вызывая частный метод new, используя send
let(:instance) { GlobalClass.send(:new) }
Хорошим преимуществом этого способа является то, что глобальное состояние не изменяется в результате выполнения ваших тестов.
Вероятно, лучший способ, от этого ответа:
let(:instance) { Class.new(GlobalClass).instance }
Это создает анонимный класс, который наследует от GlobalClass
, который хранится всеми переменными экземпляра класса. Затем он выкидывается после каждого теста, оставляя GlobalClass
нетронутым.
# singleton_spec.rb
require "singleton"
class Global
include Singleton
def initialize
puts "Initializing"
end
end
describe Global do
before do
Singleton.__init__(Global)
end
it "test1" do
Global.instance
end
it "test2" do
Global.instance
end
end
% rspec singleton_spec.rb -fd
Global
Initializing
test1
Initializing
test2
Один образец, который я видел, - это синглтон, являющийся подклассом реального класса. Вы используете версию Singleton в производственном коде, но базовый (не одиночный) класс для тестирования.
Пример:
class MyClass
attr_accessor :some_state
def initialize
@some_state = {}
end
end
class MySingletonClass < MyClass
include Singleton
end
... но я ищу лучший способ сам.
Часть моей проблемы заключается в том, что я использую JRuby и подключаюсь к настройкам системы Java, которые являются глобальными. Остальное, я думаю, я могу реорганизовать.
Одна из причин, по которой люди используют одиночные игры, потому что "глобальные переменные плохие, m'kay?" Синглтон - это глобальная переменная, секвестрированная в пространстве имен и с ленивым экземпляром. Подумайте, может ли истинная глобальная переменная упростить вещи, особенно если вам не нужна ленивая инстанция.
Реорганизовать его в класс, который можно построить несколько раз. У этого есть побочный эффект (некоторые скажут выгоду) об удалении природы Singleton из класса.
Посмотрите на это по-другому: вы обнаружили необходимость вызывать конструктор более одного раза. Почему класс должен создавать только один экземпляр? Какая польза от предоставления Singleton?
Позволяет ли RSpec выполнять предтестовые действия? Итак, вы можете добавить к вам еще один метод статического класса, который очистил бы все, что было сделано во время конструктора. Затем просто вызовите это до каждого теста.
Вы можете просто создать новый it
и заблокировать для каждой спецификации. Разделите свою спецификацию на тестируемый блок. Используйте "before" и "after", чтобы настроить и очистить все, что вы сделали.
before(:each)
и after(:each)
выполняются для каждого блока it
.