Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Let схож с subject’ом, но используется для объявления методов.
4. Собственные матчеры
module Project
module Models
describe User do # subject стал User.new
its(:value) { should be_nil }
specify { expect { subject.test }.to raise_error Errors::UserError }
# Не Project::Models::Errors::UserError
end
end
end
context "#request" do
let(:type) { 'correct_type' }
let(:params) { {type: type} }
subject { Interface.new.request(params) }
it { should be_ok }
context "with incorrect type" do
let(:type) { 'madness' }
it { should_not be_ok }
end
end
context "#request" do
let(:interface_call) { ->{ subject.some_call(type) } }
context "with incorrect type" do
let(:type) { 'Invalid type' }
specify { interface_call.should raise_error Errors::InvalidTypeError }
end
end
context "#add" do
let(:value) { subject.some_hardly_accessible_value.to_i }
specify { subject.add(20).should chage { value }.by(20) }
# Провалится, value вычислится один раз и больше не изменится
end
context "#collect_ids" do #Например, метод собирает из базы айдишники всех пользователей.
let(:user) { Fabricate(:user) } # Фабрикатором cоздается запись про юзера в базке
specify { User.all.collect_ids.should include user.id }
end
shared_context "shared_context", state: :a do # в метаданных указан state: :a - это важно
# some context
end
describe "#direct include" do
include_context "shared stuff" # прямо инклюдим shared_context в наш текущий контекст
context "subcontext_with_a_state", state: :a do
#some specs
end
context "subcontext_with_b_state", state: :b do
#other specs
end
#оба контекста будут включать в себя shared_context
end
describe "#metadata include" do
context "subcontext_with_a_state", state: :a do
#some specs
end
context "subcontext_with_b_state", state: :b do
#other specs
end
#только первый контекст включит в себя shared_context, так как совпадет по метадате
end
Важно помнить, что let вычисляется лениво, и если его выполнение имеет какие-то сайд-эффекты, то ленивое вычисление может привести к наступанию на грабли. Пример не очень хорош, но пояснит идею.
let!(:user) { Fabricate(:user) }require 'rspec'
shared_context "shared_context", state: :a do
let(:val) { 2 }
end
describe 'shared context' do
let(:val) { 1 }
context 'included by metadata', state: :a do
specify { val.should == 2 }
end
context 'not included with distinct metadata', state: :b do
specify { val.should == 1 }
end
end
RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
end
context 'some logic state', :eventmachine do
..
end
require 'rspec'
class RSpec::Core::ExampleGroup
class << self
alias_method :old_context, :context
end
def self.context *args, &block
args[0].is_a?(Symbol) ? old_context(args[0].to_s, *args, &block) : old_context(*args, &block)
end
end
RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
end
shared_context "shared_context", :key do
let(:val) { 2 }
end
describe 'shared context' do
let(:val) { 1 }
context :key do
specify { val.should == 2 }
end
context :other_key do
specify { val.should == 1 }
end
end
# rspec-core / lib / rspec / core / example_group.rb
class << self
alias_method :context, :describe
end
Применение принципа DRY в RSpec