اختبار عرض تخطيط معين باستخدام RSpec & Rails
-
01-07-2019 - |
سؤال
هل من الممكن اختبار استخدام تخطيط معين باستخدام RSpec مع Rails، على سبيل المثال، أرغب في استخدام أداة مطابقة تقوم بما يلي:
response.should use_layout('my_layout_name')
لقد وجدت أداة مطابقة use_layout عند البحث في Google ولكنها لا تعمل لأنه لا يبدو أن الاستجابة أو وحدة التحكم تحتوي على خاصية تخطيط كانت أداة المطابقة تبحث عنها.
المحلول
لقد وجدت مثالا على كيف تكتب أ use_layout
المطابق من شأنها أن تفعل ذلك تماما.إليك الرمز في حالة اختفاء هذا الرابط:
# in spec_helper.rb
class UseLayout
def initialize(expected)
@expected = 'layouts/' + expected
end
def matches?(controller)
@actual = controller.layout
#@actual.equal?(@expected)
@actual == @expected
end
def failure_message
return "use_layout expected #{@expected.inspect}, got #
{@actual.inspect}", @expected, @actual
end
def negeative_failure_message
return "use_layout expected #{@expected.inspect} not to equal #
{@actual.inspect}", @expected, @actual
end
end
def use_layout(expected)
UseLayout.new(expected)
end
# in controller spec
response.should use_layout("application")
نصائح أخرى
نشر ديفيد تشيليمسكي إجابة جيدة على منتدى روبي:
response.should render_template("layouts/some_layout")
هذا يناسبني مع edge Rails و edge RSpec on Rails:
response.layout.should == 'layouts/application'
لن يكون من الصعب تحويل هذا إلى أداة مطابقة مناسبة لك.
يوجد بالفعل أداة مطابقة وظيفية تمامًا لهذا:
response.should render_template(:layout => 'fooo')
(مواصفات 2.6.4)
كان علي أن أكتب ما يلي لإنجاز هذا العمل:
response.should render_template("layouts/some_folder/some_layout", "template-name")
هنا نسخة محدثة من المطابق.لقد قمت بتحديثه ليتوافق مع أحدث إصدار من RSpec.لقد أضفت سمات القراءة فقط ذات الصلة وقمت بإزالة تنسيق الإرجاع القديم.
# in spec_helper.rb
class UseLayout
attr_reader :expected
attr_reader :actual
def initialize(expected)
@expected = 'layouts/' + expected
end
def matches?(controller)
if controller.is_a?(ActionController::Base)
@actual = 'layouts/' + controller.class.read_inheritable_attribute(:layout)
else
@actual = controller.layout
end
@actual ||= "layouts/application"
@actual == @expected
end
def description
"Determines if a controller uses a layout"
end
def failure_message
return "use_layout expected #{@expected.inspect}, got #{@actual.inspect}"
end
def negeative_failure_message
return "use_layout expected #{@expected.inspect} not to equal #{@actual.inspect}"
end
end
def use_layout(expected)
UseLayout.new(expected)
end
بالإضافة إلى ذلك، يعمل المطابق الآن أيضًا مع التخطيطات المحددة على مستوى فئة وحدة التحكم ويمكن استخدامه على النحو التالي:
class PostsController < ApplicationController
layout "posts"
end
وفي مواصفات وحدة التحكم يمكنك ببساطة استخدام:
it { should use_layout("posts") }
هذا هو الحل الذي انتهى بي الأمر به.إنه لـ rpsec 2 و Rails 3.
لقد قمت للتو بإضافة هذا الملف في دليل المواصفات/الدعم.الرابط هو: https://Gist.github.com/971342
# spec/support/matchers/render_layout.rb
ActionView :: base.class_eval do ما لم يكن exical_methods.include؟ ('_ render_layout_with_tracking') def _render_layout_with_tracking (التخطيط ، والسكان ، & block) controller.instance_varability_set (: _ render_layout ، layout) Ain: _render_layout ،: نهاية تتبع نهاية
# يمكنك استخدام هذا المطابقة في أي مكان يمكنك الوصول إلى مثيل وحدة التحكم ، كما هو الحال في مواصفات وحدة التحكم أو التكامل.# # == مثال الاستخدام # # لا يتوقع عدم تقديم تخطيط:# controller.sould_not render_layout # تتوقع أن يتم تقديم أي تخطيط:# controller.sould Render_layout # تتوقع تطبيق APP/Layouts/Application.html.erb:# controller.seld Render_layout ('application')# controller.seld_not render_layout ('application')# controller.should_not render_layout ('mobile/application') rspec :: matchers.define: render_layout do |*args | متوقع = args.first Match do | c | الفعلي = get_layout (c) إذا توقع. nil؟!actual.nil؟# الفعلي يجب أن يكون صفراً حتى ينجح الاختبار.الاستخدام:يجب أن_not redrend_layout elsif الفعلية == متوقعة
فشل _message_for_should do | c | الفعلي = get_layout (c) إذا كان actal.nil؟&& المتوقع.لا شيء؟"من المتوقع أن يتم تقديم تخطيط ولكن لم يكن" elsif فعليًا. nil؟"تخطيط متوقع #{متوقع.
فشل _message_for_should_not do | c | الفعلي = get_layout (c) إذا توقع. nil؟"متوقع عدم وجود تخطيط ولكن #{actual.inspect} تم تقديمه" آخر "المتوقع #{متوقع.
def get_layout(controller) if template = controller.instance_variable_get(:@_rendered_layout) template.virtual_path.sub(/layouts\//, '') end end end
response.should render_template("layouts/some_folder/some_layout")
response.should render_template("template-name")
controller.active_layout.name
تناسبني.
فيما يلي نسخة من كود dmcnally الذي لا يسمح بتمرير أي وسيطات، مما يجعل "should use_layout" و"should_not use_layout" يعملان (للتأكيد على أن وحدة التحكم تستخدم أي تخطيط، أو لا تستخدم أي تخطيط، على التوالي - وهو الأمر الذي أتوقعه فقط الثاني) لتكون مفيدة حيث يجب أن تكون أكثر تحديدًا إذا كانت تستخدم تخطيطًا):
class UseLayout
def initialize(expected = nil)
if expected.nil?
@expected = nil
else
@expected = 'layouts/' + expected
end
end
def matches?(controller)
@actual = controller.layout
#@actual.equal?(@expected)
if @expected.nil?
@actual
else
@actual == @expected
end
end
def failure_message
if @expected.nil?
return 'use_layout expected a layout to be used, but none was', 'any', @actual
else
return "use_layout expected #{@expected.inspect}, got #{@actual.inspect}", @expected, @actual
end
end
def negative_failure_message
if @expected.nil?
return "use_layout expected no layout to be used, but #{@actual.inspect} found", 'any', @actual
else
return "use_layout expected #{@expected.inspect} not to equal #{@actual.inspect}", @expected, @actual
end
end
end
def use_layout(expected = nil)
UseLayout.new(expected)
end
يجب أن يكون هناك تطابقات يوفر المطابق لهذا السيناريو.(توثيق) يبدو أن هذا يعمل:
expect(response).to render_with_layout('my_layout')
وينتج رسائل فشل مناسبة مثل:
من المتوقع أن يتم العرض باستخدام تخطيط "calendar_layout"، ولكن يتم عرضه باستخدام "application"، و"application"
تم اختباره مع rails 4.2
, rspec 3.3
و shoulda-matchers 2.8.0
يحرر:يوفر musta-matchers هذه الطريقة.ينبغي::Matchers::ActionController::RenderWithLayoutMatcher