كيفية اختبار مشكلة وحدة التحكم في Rails 4
-
21-12-2019 - |
سؤال
ما هي أفضل طريقة للتعامل مع اختبار المخاوف عند استخدامها في وحدات تحكم Rails 4؟قل أن لدي قلقًا تافهًا Citations
.
module Citations
extend ActiveSupport::Concern
def citations ; end
end
السلوك المتوقع قيد الاختبار هو أن أي وحدة تحكم تتضمن هذا الاهتمام ستحصل على هذا citations
نقطة النهاية.
class ConversationController < ActionController::Base
include Citations
end
بسيط.
ConversationController.new.respond_to? :yelling #=> true
ولكن ما هي الطريقة الصحيحة لاختبار هذا القلق بمعزل عن غيره؟
class CitationConcernController < ActionController::Base
include Citations
end
describe CitationConcernController, type: :controller do
it 'should add the citations endpoint' do
get :citations
expect(response).to be_successful
end
end
لسوء الحظ، هذا فشل.
CitationConcernController
should add the citations endpoint (FAILED - 1)
Failures:
1) CitationConcernController should add the citations endpoint
Failure/Error: get :citations
ActionController::UrlGenerationError:
No route matches {:controller=>"citation_concern", :action=>"citations"}
# ./controller_concern_spec.rb:14:in `block (2 levels) in <top (required)>'
هذا مثال مفتعل.في تطبيقي، أحصل على خطأ مختلف.
RuntimeError:
@routes is nil: make sure you set it in your test's setup method.
المحلول
ستجد العديد من النصائح التي تخبرك باستخدام الأمثلة المشتركة وتشغيلها في نطاق وحدات التحكم المضمنة لديك.
أنا شخصيا أجد ذلك مبالغا فيه وأفضل إجراء اختبار الوحدة بمعزل عن الآخر ثم استخدام اختبار التكامل للتأكد من سلوك وحدات التحكم الخاصة بي.
طريقة 1:دون التوجيه أو اختبار الاستجابة
إنشاء وحدة تحكم وهمية واختبار طرقها:
describe MyControllerConcern do
before do
class FakesController < ApplicationController
include MyControllerConcern
end
end
after { Object.send :remove_const, :FakesController }
let(:object) { FakesController.new }
describe 'my_method_to_test' do
it { expect(object).to eq('expected result') }
end
end
الطريقة الثانية:استجابة الاختبار
عندما تحتوي مخاوفك على توجيه أو تحتاج إلى اختبار الاستجابة والعرض وما إلى ذلك...تحتاج إلى إجراء الاختبار الخاص بك مع وحدة تحكم مجهولة.يسمح لك هذا بالوصول إلى جميع أساليب rspec والمساعدين المتعلقين بوحدة التحكم:
describe MyControllerConcern, type: :controller do
controller(ApplicationController) do
include MyControllerConcern
def fake_action; redirect_to '/an_url'; end
end
before { routes.draw {
get 'fake_action' => 'anonymous#fake_action'
} }
describe 'my_method_to_test' do
before { get :fake_action }
it { expect(response).to redirect_to('/an_url') }
end
end
يمكنك أن ترى أنه يتعين علينا تغليف وحدة التحكم المجهولة في ملف controller(ApplicationController)
.إذا كانت فصولك موروثة من فئة أخرى غير ApplicationController
, ، سوف تحتاج إلى التكيف مع هذا.
أيضًا لكي يعمل هذا بشكل صحيح، يجب أن تعلن في ملفك spec_helper.rb ملف:
config.infer_base_class_for_anonymous_controllers = true
ملحوظة:استمر في اختبار أن مخاوفك متضمنة
من المهم أيضًا اختبار ما إذا كانت الفئة التي تهتم بها مدرجة في الفئات المستهدفة، سطر واحد يكفي:
describe SomeTargetedController do
describe 'includes MyControllerConcern' do
it { expect(SomeTargetedController.ancestors.include? MyControllerConcern).to eq(true) }
end
end
نصائح أخرى
تبسيط الطريقة الثانية من الإجابة الأكثر تصويتًا.
لكنني أفضل anonymous controller
مدعوم في rspec http://www.relishapp.com/rspec/rspec-rails/docs/controller-specs/anonymous-controller
ستفعل:
describe ApplicationController, type: :controller do
controller do
include MyControllerConcern
def index; end
end
describe 'GET index' do
it 'will work' do
get :index
end
end
end
لاحظ أنك تحتاج إلى وصف ApplicationController
وقم بتعيين النوع في حالة عدم حدوث ذلك افتراضيًا.
قد تبدو إجابتي أكثر تعقيدًا بعض الشيء من إجابات @Benj و@Calin، ولكن لها مزاياها.
describe Concerns::MyConcern, type: :controller do
described_class.tap do |mod|
controller(ActionController::Base) { include mod }
end
# your tests go here
end
أولاً، أوصي باستخدام وحدة تحكم مجهولة وهي فئة فرعية من ActionController::Base
, ، لا ApplicationController
ولا أي وحدة تحكم أساسية أخرى محددة في التطبيق الخاص بك.بهذه الطريقة يمكنك اختبار المشكلة بمعزل عن أي من وحدات التحكم الخاصة بك.إذا كنت تتوقع أن يتم تعريف بعض الأساليب في وحدة التحكم الأساسية، فما عليك سوى إيقافها.
علاوة على ذلك، من الجيد تجنب إعادة كتابة اسم الوحدة المعنية لأنه يساعد على تجنب أخطاء النسخ واللصق.للأسف، described_class
لا يمكن الوصول إليه في كتلة تم تمريرها إلى controller(ActionController::Base)
, ، لذلك أستخدم #tap
طريقة لإنشاء ربط آخر يخزن described_class
في متغير محليوهذا مهم بشكل خاص عند العمل مع واجهات برمجة التطبيقات ذات الإصدارات.في مثل هذه الحالة، من الشائع جدًا نسخ حجم كبير من وحدات التحكم عند إنشاء إصدار جديد، ومن السهل جدًا ارتكاب مثل هذا الخطأ الدقيق في النسخ واللصق.
أنا أستخدم طريقة أبسط لاختبار مخاوف تحكم الخاصة بي، لست متأكدا مما إذا كانت هذه هي الطريقة الصحيحة ولكن بدا أبسطا بكثير أن ما سبق ويعززني، ونوعه من استخدام نطاق وحدات التحكم المضمنة.واسمحوا لي أن أعرف إذا كان هناك أي مشاكل بهذه الطريقة. تحكم العينة:
giveacodicetagpre.نهاية
قلق تحكم الخاص بي:
giveacodicetagpre.اختبار المواصفات للقلق:
giveacodicetagpre.