2015-11-09 2 views
3

Я пишу некоторые rspec для тестирования некоторых модулей, которые правильно реализуют их поведение.Использование описанного_класса при включении тестируемого модуля

Модуль выглядит следующим образом:

module Under::Test 
    def some_behaviour 
    end 
end 

Я не могу сделать это в RSpec:

describe Under::Test do 
    subject {Class.new{include described_class}.new} 

В точке #described_class называется, она уже не может быть решена, поскольку само является экземпляр класса, который не имеет метода #describe_class. Поэтому я вынужден повторить себя:

subject {Class.new{include Under::Test}.new} 

Или использовать его в спецификации по-другому, как оно используется моими клиентами:

subject {Object.new.extend described_class} 

Это имеет тот же конечный эффект, но что-то в я думаю, что если я попрошу своих клиентов include Under::Test, тогда тесты должны быть близки к тому, как они используются ими, насколько это возможно.

Я могу использовать свойство закрытия, чтобы исправить это, но мне интересно, не лучше ли это. У этого есть запах кода?

describe Under::Test do 
    subject {mudule = described_class;Class.new{include mudule}.new} 

    it 'has some behaviour' do 
    expect(subject.some_behaviour).to be 
    end 
end 

Заметь, я также спросил г/рубин на Reddit, кто-то там предложил:

subject {Class.new.include(described_class).new} 

, которые могут быть как я иду.

+0

Я предпочитаю просто повторять имя модуля. Использование локальной переменной ('mudule') является умным способом избежать дублирования, но я считаю, что ясность более важна, чем СУХОЕ, особенно в спецификации. –

ответ

4

Если ваша конечная цель - include текущий described_class модуль во вновь созданном Class, как насчет следующего обходного пути?

RSpec.describe NewModule do 
    let(:test_class) do 
    Class.new.tap do |klass| 
     klass.include(described_class) 
    end 
    end 

    specify do 
    expect(test_class.ancestors).to include described_class # passes 
    end 
end 

А вот пример того, в том числе методов модуля, в объекте:

module NewModule 
    def identity 
    itself 
    end 
end 

RSpec.describe NewModule do 
    let(:one) do 
    1.tap do |obj| 
     obj.class.include(described_class) 
    end 
    end 

    specify do 
    expect(one.identity).to eq 1 # passes 
    end 
end 

Обратите внимание, что метод include для Class не в Ruby-v2 + private. Если вы используете более старую версию, вы должны использовать klass_name.send(:include, described_class)

+0

thanx @Humza - этот публичный совет #include также вышел в том же обсуждении reddit – Leif

2

Я думаю, что оба ваших решений просто отлично, мне нравится немного больше

Object.new.extend described_class 

для его читаемости и понятности. Если вы хотите использовать подход Class.new, я думаю, что это нормально повторять имя модуля, как сказал Джаред, читаемость здесь важнее, чем сухость.

Смежные вопросы