{"id":267613,"date":"2015-11-06T11:05:02","date_gmt":"2015-11-06T08:05:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=267613"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=267613","title":{"rendered":"\u0420\u0435\u0446\u0435\u043f\u0442\u044b \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Ruby \u0438 Rails \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439"},"content":{"rendered":"<p>       <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/6ba\/386\/d57\/6ba386d5794b3b6ba6f689f0a59ce8e9.png\" alt=\"image\"\/><\/p>\n<p>  \u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435 \u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430\u0445, \u043f\u0440\u0438\u0435\u043c\u0430\u0445 \u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u0445 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. \u0420\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0442\u043e, \u043a\u0430\u043a \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0435\u0433\u043e, \u043c\u0435\u043d\u044c\u0448\u0435 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434, \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0438\u0445 \u0431\u044b\u043b\u043e \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c, \u0438 \u043a\u0430\u043a \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445.<\/p>\n<p>  \u041a\u043e\u043c\u0443 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e?<\/p>\n<ul>\n<li>\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0435\u0434\u0430\u0432\u043d\u043e.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u0438\u0448\u0435\u0442\u0435 \u0442\u0435\u0441\u0442\u044b \u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u0432 \u043d\u0438\u0445 \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u044b, \u0438\u043b\u0438 \u043c\u043e\u0436\u043d\u043e \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u0438\u0445.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u0438\u0448\u0435\u0442\u0435 \u0442\u0435\u0441\u0442\u044b \u0438\u0437\u0440\u0435\u0434\u043a\u0430 \u0438\u043b\u0438 \u043d\u0435 \u043f\u0438\u0448\u0435\u0442\u0435 \u0441\u043e\u0432\u0441\u0435\u043c, \u0442\u0430\u043a \u043a\u0430\u043a \u0432\u0430\u043c \u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0438\u043b\u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u044d\u0442\u043e \u0434\u043e\u043b\u0433\u043e.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u0432\u044b \u043c\u0430\u0441\u0442\u0435\u0440 \u0432 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0432\u044b \u0443\u0437\u043d\u0430\u0435\u0442\u0435 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u0438 \u0438\u043b\u0438 \u043d\u0430\u0439\u0434\u0435\u0442\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u043c\u0435\u043b\u043e\u0447\u0435\u0439.<\/li>\n<\/ul>\n<p><a name=\"habracut\"><\/a><br \/>  \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u043a\u043e\u0434\u0430 \u044f \u0431\u0443\u0434\u0443 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u0434\u043b\u044f RSpec, \u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0438\u0437 \u043d\u0438\u0445 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u0441 MiniTest (\u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0434\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0432\u0435\u0441\u0442\u0438 \u043d\u0430\u043f\u0438\u043b\u044c\u043d\u0438\u043a\u043e\u043c). \u0422\u0435\u043c, \u043a\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f RSpec, \u043d\u043e \u0435\u0449\u0435 \u043d\u0435 \u0447\u0438\u0442\u0430\u043b <a href=\"http:\/\/betterspecs.org\/\">betterspecs.org<\/a>, \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u2014 \u0442\u0430\u043c \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u0445\u043e\u0440\u043e\u0448\u043e, \u0430 \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435 \u043d\u0430\u0434\u043e.<\/p>\n<h4>\u041d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043d\u044c<\/h4>\n<p>  <\/p>\n<h5>RSpec DSL<\/h5>\n<p>  RSpec \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0442\u044c \u0438\u043d\u0441\u0442\u0430\u043d\u0441- \u0438 \u043a\u043b\u0430\u0441\u0441-\u043c\u0435\u0442\u043e\u0434\u044b \u0432 \u0442\u0435\u043a\u0441\u0442\u0435 \u0441\u043f\u0435\u043a\u0430 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432\u043e \u0432\u0441\u0435\u0445 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430\u0445. \u0415\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0445\u044d\u043b\u043f\u0435\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 \u044d\u0442\u043e\u043c \u043f\u043e\u043c\u043e\u0433\u0443\u0442.<\/p>\n<h5>let<\/h5>\n<p>  \u0412 RSpec <code>let<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u00ab\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445\u00bb. \u041e\u043d \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441-\u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u043b\u043e\u043a\u0430, \u0432\u044b\u0447\u0435\u0441\u043b\u0435\u043d\u043d\u044b\u0439 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u0442\u0435\u0441\u0442\u0430. \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043b\u0435\u043d\u0438\u0432\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u0441\u0442\u0440\u0430\u0448\u043d\u043e\u0433\u043e, \u0435\u0441\u043b\u0438 \u0432\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 `let` \u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0435\u0433\u043e \u0432 \u0447\u0430\u0441\u0442\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u2014 \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e \u043d\u0435 \u043f\u043e\u0432\u043b\u0438\u044f\u0435\u0442. \u0411\u043b\u043e\u043a \u043e\u0434\u043d\u043e\u0433\u043e <code>let<\/code> \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0434\u0440\u0443\u0433\u043e\u0433\u043e <code>let<\/code> \u0438\u043b\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 <code>super<\/code>:<\/p>\n<pre><code class=\"ruby\">let(:project) { Project.new(project_attrs) } let(:project_attrs) { {name: 'new_name', description: 'new_description'} }  context 'when empty name is given' do   let(:project_attrs) { super().merge!(name: '') }   # \u0412 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 ruby super \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c, \u044f\u0432\u043d\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b.   # \u0422\u0443\u0442 \u0438\u0445 \u043d\u0435\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 (). end <\/code><\/pre>\n<p>  \u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 <code>let<\/code> \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u043b\u043e\u043a\u0430 \u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c\u044b\u0435 \u0438\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u2014 \u044d\u0442\u043e, \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u0442\u0435\u0441\u0442\u0430. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 <code>let<\/code> \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0448\u043e\u0440\u0442\u043a\u0430\u0442\u043e\u0432. \u0415\u0441\u043b\u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u0442\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u043c\u0435\u0442\u043e\u0434.<\/p>\n<h5>subject<\/h5>\n<p>  <code>subject<\/code> \u2014 \u044d\u0442\u043e \u00ab\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u044b\u0439\u00bb <code>let<\/code>. \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432\u0441\u0435 \u043c\u0430\u0442\u0447\u0435\u0440\u044b, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044c, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043a <code>subject<\/code>.<\/p>\n<pre><code class=\"ruby\">describe '#valid?' do   subject { user.valid? }    it { should eq true }   # \u0438\u043b\u0438   it { is_expected.to eq true }    # subject \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 c \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u043c\u0438 \u043c\u0430\u0442\u0447\u0435\u0440\u0430\u043c\u0438   context 'when name is empty' do     it 'adds error' do       expect { subject }.to change(user.errors, :any?).to true     end   end end <\/code><\/pre>\n<p>  \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <code>subject<\/code> \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u043f\u043e\u0432\u044b\u0448\u0430\u0435\u0442 \u0447\u0438\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u0432\u044b \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 \u043e\u0442 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0432 <code>describe<\/code>. \u0412 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u0432\u0430\u043c \u0443\u0434\u0430\u0441\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 <code>subject<\/code> \u043d\u0430 <code>describe<\/code>, \u0432\u043b\u0438\u044f\u044f \u043d\u0430 \u0435\u0433\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>let<\/code> \u0432\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430\u0445:<\/p>\n<pre><code class=\"ruby\"># \u041f\u0440\u0438\u043c\u0435\u0440 \u0442\u0435\u0441\u0442\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430  RSpec.describe ProjectsController do   describe '#index' do     subject { get :index }      it { should redirect_to new_user_session_path }      context 'for signed in user' do       sign_in { create(:user) } # \u0445\u044d\u043b\u043f\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043b\u043e\u0433\u0438\u043d\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f       it { should be_forbidden }        context 'with permissions' do         add_permissions(:manager) # \u0445\u044d\u043b\u043f\u0435\u0440 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0430\u0432 \u0437\u0430\u043b\u043e\u0433\u0438\u043d\u0435\u043d\u043e\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e         it { should be_ok }       end     end   end    # \u0422\u0443\u0442 \u0438 \u043d\u0438\u0436\u0435 \u043e\u043f\u0443\u0441\u0442\u0438\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u043c\u0435\u0441\u0442\u0430   describe '#create' do     subject { post :create, project: resource_params }     let(:resource_params) { {name: 'new_project'} }      it 'creates resource and redirects to its page' do       expect { subject }.to change(Project, :count).by(1)       resource = Project.last       expect(project.name).to eq 'new_name'       expect(subject).to redirect_to project_path(resource)     end      context 'when params are invalid' do       let(:resource_params) { super().merge!(name: '') }        it { should render_template :new }       it 'doesnt create resource' do         expect { subject }.to_not change(Project, :count)       end     end   end end <\/code><\/pre>\n<p>  \u0412 \u0442\u0435\u0441\u0442\u0430\u0445 `type: :request` <code>get<\/code>, <code>post<\/code> \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 <code>response<\/code>. \u041d\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0448 <code>subject<\/code>, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043d\u0438\u0445 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u043f\u043e\u0434\u0445\u043e\u0434:<\/p>\n<pre><code class=\"ruby\">subject do   get '\/projects'   response end <\/code><\/pre>\n<p>  \u0414\u043e \u044d\u0442\u043e\u0433\u043e \u0432 <code>subject<\/code> \u043c\u044b \u043f\u043e\u043c\u0435\u0449\u0430\u043b\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u043b\u0438. \u0427\u0430\u0441\u0442\u043e \u0431\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043c\u0435\u043d\u044c\u0448\u0435, \u0447\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c. \u0412 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0442 \u043b\u044f\u043c\u0431\u0434\u044b:<\/p>\n<pre><code class=\"ruby\">describe '#like!' do   subject { -&gt; { user.like! post } }    it { should change(post, :likes_count).by(1) }   it { should change(user, :favorite_posts).by(post) }    context 'when post is already favorite' do     before { subject.call }     it { should raise_error \/Already favorite\/ }   end end <\/code><\/pre>\n<p>  \u041b\u044f\u043c\u0431\u0434\u044b \u0443\u0434\u043e\u0431\u043d\u044b \u0442\u0430\u043a\u0436\u0435 \u0432 \u0442\u0435\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445, \u043a\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043c\u0435\u0442\u043e\u0434\u0430 \u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438 \u043d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442:<\/p>\n<pre><code class=\"ruby\">describe '.cleanup_str' do   subject { -&gt;(*args) { described_class.cleanup_str(*args) } }    it 'removes non-word symbols' do     expect(subject.call('xY12')).to eq 'xY12'     expect(subject.call('x+Y-1_2')).to eq 'xY12'     expect(subject.call('x.Y 1;2')).to eq 'xY12'   end end <\/code><\/pre>\n<p>  \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0432\u043e \u0432\u0441\u0435\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u043c\u044b \u043d\u0435 \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u043c\u0443 \u043c\u0435\u0442\u043e\u0434\u0443, \u043a\u0440\u043e\u043c\u0435 \u043a\u0430\u043a \u0447\u0435\u0440\u0435\u0437 <code>subject<\/code>.<\/p>\n<h6>its<\/h6>\n<p>  \u0414\u043b\u044f RSpec \u0435\u0441\u0442\u044c \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 \u043f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/github.com\/rspec\/rspec-its\">rspec-its<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u043d\u0435\u0441\u043b\u0438 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0433\u0435\u043c \u0432 \u0442\u0440\u0435\u0442\u044c\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438. C \u044d\u0442\u043e\u0439 \u0448\u0442\u0443\u043a\u043e\u0439 \u0442\u0435\u0441\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0441\u0442\u0430\u0442\u044c \u0435\u0449\u0451 \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u0435\u0435 \u0438 \u0432\u044b\u0440\u0430\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u0435\u0435. <a href=\"https:\/\/github.com\/carrierwaveuploader\/carrierwave\/blob\/83493b9d845b1247f720495962ab4e008f5e3f97\/spec\/sanitized_file_spec.rb#L223-L263\">\u0412\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440<\/a>, \u0433\u0434\u0435 <code>its<\/code> \u0442\u043e\u0447\u043d\u043e \u0431\u044b \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u0441\u044f.<\/p>\n<p>  \u041d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0439, \u043d\u043e \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u043f\u0440\u0438\u0451\u043c \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <code>its<\/code> \u0441 \u043b\u044f\u043c\u0431\u0434\u0430\u043c\u0438:<\/p>\n<pre><code class=\"ruby\">RSpec.describe ProjectsController do   let(:resource) { create(:project) }    describe '#update' do     subject { -&gt; { patch :update, id: project, project: resource_params } }     let(:resource_params) { {name: 'updated_name'} }      it { should change { resource.reload.name }.to 'updated_name' }     its(:call) { should redirect_to project_path(resource) }   end end <\/code><\/pre>\n<p>  \u0415\u0449\u0451 \u043e\u0434\u043d\u0430 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f, \u0433\u0434\u0435 <code>its<\/code> \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u0441\u044f \u2014 \u043f\u0440\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 JSON \u043e\u0442\u0432\u0435\u0442\u043e\u0432. \u0415\u0441\u043b\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>ActionDispatch::TestResponse#json_body<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 <code>#body<\/code> \u0447\u0435\u0440\u0435\u0437 <code>JSON.parse<\/code> \u0438 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 <code>Mash<\/code> (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/github.com\/printercu\/rails_stuff\/blob\/master\/lib\/rails_stuff\/test_helpers\/response.rb\">\u0442\u0430\u043a<\/a>), \u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043f\u043e\u043b\u044f \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e:<\/p>\n<pre><code class=\"ruby\">RSpec.describe UsersController do   let(:resourse) { create(:user) }    describe '#show' do     subject { get :show, id: resource, format: :json }      its('json_body.keys') { should contain_exactly(*w(name projects avatar)) }     its('json_body.avatar.keys') { should contain_exactly(*w(url size)) }     its('json_body.projects.first.keys') { should contain_exactly(*w(name created_at)) }   end end <\/code><\/pre>\n<p>  <\/p>\n<h5>described_class<\/h5>\n<p>  <code>described_class<\/code> \u2014 \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u00ab\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u044b\u0439\u00bb <code>let<\/code>. \u042d\u0442\u043e \u0445\u044d\u043b\u043f\u0435\u0440 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043e\u0431\u044a\u0435\u043a\u0442\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u0432 <code>RSpec.describe<\/code>. \u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0435\u0433\u043e \u0432\u043c\u0435\u0441\u0442\u043e \u044f\u0432\u043d\u043e\u0433\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0443\u043b\u044f \u043a\u043e\u0434 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u00ab\u043e\u0431\u043e\u0441\u043e\u0431\u043b\u0435\u043d\u043d\u044b\u0439\u00bb: \u043a\u043b\u0430\u0441\u0441 \u043a\u0430\u043a \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 <code>describe<\/code>, \u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u043d\u0435\u043c\u0443 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043a\u0430\u043a \u043a \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0443. \u0422\u0430\u043a\u043e\u0439 \u043a\u043e\u0434 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u0435\u043d \u0434\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u0435\u0433\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u043e\u0449\u0435 \u0432\u044b\u0434\u0435\u043b\u044f\u0442\u044c \u0432 <code>shared_examples<\/code>. <code>described_class<\/code> \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0441 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430\u043c\u0438: <code>should raise_error described_class::Error<\/code>, \u0438\u043b\u0438 <code>described_class::LIMIT<\/code>.<\/p>\n<h5>\u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445<\/h5>\n<p>  \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0449\u0438\u0435 \u043d\u0435\u0439\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432\u043e \u0432\u0441\u0435\u0445 \u0442\u0435\u0441\u0442\u0430\u0445. \u041c\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <code>instance<\/code> \u0434\u043b\u044f \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0438 <code>resource<\/code> \u0434\u043b\u044f \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432\/\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u041e\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043b\u044e\u0441\u043e\u0432 \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u044f \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u043d\u0435 \u043c\u043e\u0433\u0443, \u043d\u043e \u0441\u0443\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0442\u0435\u0441\u0442\u044b \u043f\u0438\u0448\u0443\u0442\u0441\u044f \u0438 \u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u0435\u0435.<\/p>\n<h5>shared_examples<\/h5>\n<p>  \u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 <code>shared_examples<\/code> \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u043b\u044e\u0431\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430, \u0438 \u043e\u043d\u0438 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0432\u043d\u0435 \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430. \u042d\u0442\u043e \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430\u0445:<\/p>\n<pre><code class=\"ruby\">RSpec.describe ProjectsController do   let(:resource) { create(:project) }    shared_examples 'rendering resource' do     it { should be_ok }     its(:json_body) { should include 'id' =&gt; resource.id, 'name' =&gt; resource.name }   end    describe '#show' do     subject { get :show, id: resource.id }     include_examples 'rendering resource'   end    describe '#search' do     subject { get :search, q: resource.name }     include_examples 'rendering resource'   end <\/code><\/pre>\n<p>  \u0418\u043d\u043e\u0433\u0434\u0430 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 <code>shared_examples<\/code> \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0438\u043b\u0438 \u0434\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043e\u0434\u043d\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0434\u043b\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432. \u0412 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u0440\u0443\u043f\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 <code>shared_examples<\/code> \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043c\u0435\u043d\u044c\u0448\u0435 \u0438 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u044b \u043c\u0435\u0436\u0434\u0443 \u0444\u0430\u0439\u043b\u0430\u043c\u0438. \u041d\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u043a <code>include_examples<\/code>:<\/p>\n<pre><code class=\"ruby\">RSpec.shared_examples 'hooks controller #create' do |**options|   describe '#create' do     subject { post :create, params }      context 'on success' do       let(:params) { valid_params }       # \u041e\u0431\u0449\u0438\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438       it { should change { something } }       # \u041e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438       instance_eval(&options[:on_success]) if options[:on_success]     end      context 'on failure' do       let(:params) { invalid_params }       it { should_not change { something } }              if options[:on_failure]         instance_eval(&options[:on_failure])       else         its(:status) { should eq 422 } # \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435       end     end   end end  RSpec.describe BrandedHooksController do   include_examples 'hooks controller #create',     on_success: -&gt; { its(:json_body) { should eq 'status' =&gt; 'ok' } },     on_failure: -&gt; { its(:json_body) { should eq 'status' =&gt; 'rejected' } } do       let(:valid_params) { {type: 'hook'} }       let(:invalid_params) { {type: 'unsupported'} }     end end <\/code><\/pre>\n<p>  <\/p>\n<h4>\u0423\u0441\u043a\u043e\u0440\u044f\u0435\u043c \u0442\u0435\u0441\u0442\u044b<\/h4>\n<p>  \u042f \u043d\u0435 \u0431\u0443\u0434\u0443 \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e spring\/zeus\/spork\/\u0434\u0440., \u0430 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0435\u0449\u0451 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<h5>\u041e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0434\u043e\u043b\u0433\u0438\u0435 \u0442\u0435\u0441\u0442\u044b<\/h5>\n<p>  \ud83d\ude42 \u041d\u043e \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u043f\u043e\u0434\u043e\u0439\u0442\u0438 \u043f\u043e \u043c\u043d\u043e\u0433\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c, \u043d\u043e \u0435\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438, \u0442\u0440\u0435\u0431\u0443\u044e\u0449\u0438\u0435 \u0434\u043e\u043b\u0433\u0438\u0445 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439, \u043f\u043e\u043c\u0435\u0442\u044c\u0442\u0435 \u0438\u0445 \u0442\u044d\u0433\u043e\u043c \u0432 RSpec \u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0438\u0445 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u043e\u0431\u044b\u0447\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 <code>rspec<\/code>. \u042d\u0442\u043e \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u044b \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0434\u043e\u043b\u0433\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432 \u0411\u0414, \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438.<\/p>\n<pre><code class=\"ruby\"># spec_helper.rb  # Exclude some tags by default. Running 1 file won't use exclusions. # Use `FULL=true bin\/rspec` to disable filters. if (!ENV.key?('FULL') || !ENV.key?('CI')) && config.files_to_run.size &gt; 1   config.filter_run_excluding :external, :elastics end  # some_job_spec.rb describe '.process_file', :external do   it 'does somithing heavy' end <\/code><\/pre>\n<p>  \u0421 \u0442\u0430\u043a\u0438\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u044b \u0434\u0436\u043e\u0431\u044b \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043d\u043e \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u0435\u043d\u044b, \u0435\u0441\u043b\u0438 \u0432\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435:  <\/p>\n<ul>\n<li>\u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b <code>some_job_spec.rb<\/code><\/li>\n<li>`FULL=true bin\/rspec`<\/li>\n<li>\u043d\u0430 CI \u0441\u0435\u0440\u0432\u0435\u0440\u0435 (\u0435\u0441\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 envar CI)<\/li>\n<\/ul>\n<p>  <\/p>\n<h5>\u041e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0438\u043d\u0433 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439<\/h5>\n<p>  \u041f\u043e\u043b\u0430\u0433\u0430\u044e, \u044d\u0442\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0451\u0442 \u0432\u0441\u0435\u043c, \u043a\u0442\u043e \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442. \u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 fixtures, \u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435-\u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u043c\u043e\u0434\u0435\u043b\u0438, \u0442\u043e \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0442\u0435\u0441\u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430, \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  \u0421\u043f\u043e\u0441\u043e\u0431 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u0412 \u0442\u0435\u0441\u0442\u0430\u0445 \u0436\u0435 \u043f\u043e\u0434\u0445\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c: \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0438\u043d\u0433 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u043e \u0442\u044d\u0433\u0443 \u0438\u043b\u0438 \u0432 around-\u0445\u0443\u043a\u0435.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f carrierwave<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"ruby\">module SpecHelpers   # All image uploaders are descendants of ImageUploader. This module   # toggles &lt;code&gt;enable_processing&lt;\/code&gt; of it and all its descendants.   module ImageProcessing     module_function      # Overwrites cached values in ancestors.     def enable_processing=(val)       ImageUploader.enable_processing = val       ImageUploader.descendants.each { |x| x.enable_processing = val }     end      def with_processing(val)       old_value = ImageUploader.enable_processing       self.enable_processing = val       yield     ensure       self.enable_processing = old_value unless old_value == ImageUploader.enable_processing     end   end end  # rails_helper.rb around process_images: true do |ex|   SpecHelpers::ImageProcessing.with_processing(true) { ex.run } end <\/code><\/pre>\n<\/div>\n<\/div>\n<h4>\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u043c\u0435\u043b\u043e\u0447\u0438<\/h4>\n<p>  <\/p>\n<ul>\n<li>RSpec3 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <code>.rspec<\/code> \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0445 \u0444\u043b\u0430\u0433\u043e\u0432. \u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432 \u043d\u0451\u043c \u0435\u0441\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0430 `&#8212;require spec_helper`. \u0415\u0441\u043b\u0438 \u0435\u0451 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430 `&#8212;require rails_helper`, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c `require &#8216;rails_helper&#8217;` \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u043f\u0435\u043a\u0435.<\/li>\n<li>^^<br \/> \n<pre><code class=\"ruby\"># spec_helper.rb require 'bigdecimal' BigDecimal.class_eval do   alias_method :inspect_orig, :inspect   alias_method :inspect, :to_s end <\/code><\/pre>\n<p>  <\/li>\n<\/ul>\n<p>  \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0434\u0435\u043b\u0438\u0442\u0435\u0441\u044c \u0432\u0430\u0448\u0438\u043c\u0438 \u0440\u0435\u0446\u0435\u043f\u0442\u0430\u043c\u0438 \u0432 \u043a\u043e\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445.               <\/p>\n<div class=\"clear\"><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/269723\/\"> http:\/\/habrahabr.ru\/post\/269723\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>       <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/6ba\/386\/d57\/6ba386d5794b3b6ba6f689f0a59ce8e9.png\" alt=\"image\"\/><\/p>\n<p>  \u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435 \u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430\u0445, \u043f\u0440\u0438\u0435\u043c\u0430\u0445 \u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u0445 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. \u0420\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0442\u043e, \u043a\u0430\u043a \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0435\u0433\u043e, \u043c\u0435\u043d\u044c\u0448\u0435 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434, \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0438\u0445 \u0431\u044b\u043b\u043e \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c, \u0438 \u043a\u0430\u043a \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445.<\/p>\n<p>  \u041a\u043e\u043c\u0443 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e?<\/p>\n<ul>\n<li>\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0435\u0434\u0430\u0432\u043d\u043e.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u0438\u0448\u0435\u0442\u0435 \u0442\u0435\u0441\u0442\u044b \u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u0432 \u043d\u0438\u0445 \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u044b, \u0438\u043b\u0438 \u043c\u043e\u0436\u043d\u043e \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u0438\u0445.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u0438\u0448\u0435\u0442\u0435 \u0442\u0435\u0441\u0442\u044b \u0438\u0437\u0440\u0435\u0434\u043a\u0430 \u0438\u043b\u0438 \u043d\u0435 \u043f\u0438\u0448\u0435\u0442\u0435 \u0441\u043e\u0432\u0441\u0435\u043c, \u0442\u0430\u043a \u043a\u0430\u043a \u0432\u0430\u043c \u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0438\u043b\u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u044d\u0442\u043e \u0434\u043e\u043b\u0433\u043e.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u0432\u044b \u043c\u0430\u0441\u0442\u0435\u0440 \u0432 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0432\u044b \u0443\u0437\u043d\u0430\u0435\u0442\u0435 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u0438 \u0438\u043b\u0438 \u043d\u0430\u0439\u0434\u0435\u0442\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u043c\u0435\u043b\u043e\u0447\u0435\u0439.<\/li>\n<\/ul>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-267613","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/267613","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=267613"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/267613\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=267613"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=267613"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=267613"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}