ruby on rails - متى يستخدم RSpec let()؟




ruby-on-rails tdd (6)

"قبل" بشكل افتراضي يعني before(:each) . Ref The Rspec Book، copyright 2010، page 228.

before(scope = :each, options={}, &block)

أستخدم من before(:each) لترتيب بعض البيانات لكل مجموعة أمثلة دون الحاجة إلى استدعاء طريقة let لإنشاء البيانات في كتلة "it". رمز أقل في كتلة "it" في هذه الحالة.

يمكنني استخدام ما إذا كنت أريد بعض البيانات في بعض الأمثلة دون غيرها.

كل من قبل والسماح رائعة لتجف حتى كتل "ذلك".

لتجنب أي التباس ، "دعونا" ليس هو نفسه كما كان من before(:all) . "Let" يعيد تقييم أسلوبه وقيمته لكل مثال ("it") ، ولكن يخبئ القيمة عبر مكالمات متعددة في نفس المثال. يمكنك قراءة المزيد عنه هنا: relishapp.com/rspec/rspec-core/v/2-6/docs/helper-methods/…

أميل إلى استخدام قبل كتل لتعيين متغيرات الحالة. ثم استخدم هذه المتغيرات عبر الأمثلة. جئت مؤخرا على let() . وفقا لوثائق RSPec ، يتم استخدامه ل

... لتحديد طريقة المساعد memoized. سيتم تخزين القيمة مؤقتًا عبر عدة مكالمات في نفس المثال ولكن ليس عبر الأمثلة.

كيف يختلف هذا عن استخدام متغيرات الحالة في ما قبل الكتل؟ ومتى يجب عليك استخدام let() مقابل من before() ؟


أستخدم ميزة اختبار استجابات HTTP 404 في مواصفات واجهة برمجة التطبيقات باستخدام السياقات.

لإنشاء هذا المورد ، أستخدمه let! . ولكن لتخزين معرف الموارد ، وأنا استخدم let . ألقِ نظرة على الشكل الذي تبدو عليه:

let!(:country)   { create(:country) }
let(:country_id) { country.id }
before           { get "api/countries/#{country_id}" }

it 'responds with HTTP 200' { should respond_with(200) }

context 'when the country does not exist' do
  let(:country_id) { -1 }
  it 'responds with HTTP 404' { should respond_with(404) }
end

التي تحافظ على المواصفات نظيفة وقابلة للقراءة.


بشكل عام ، let() هو بناء الجملة أجمل ، وأنه يوفر لك كتابة رموز @name كل مكان. ولكن ، ميمور التحذير! لقد وجدت let() أيضا يقدم الحشرات خفية (أو على الأقل خدش الرأس) لأن المتغير لا موجود حقا حتى تحاول استخدامه ... أخبر علامة حكاية: إذا مضيفا puts بعد let() لرؤية ذلك المتغير هو الصحيح يسمح للمواصفات لتمرير ، ولكن دون puts يفشل المواصفات - لقد وجدت هذه الدقة.

لقد وجدت أيضا أن let() لا يبدو مخبأ في جميع الظروف! لقد كتبت ذلك في مدونتي: http://technicaldebt.com/?p=1242

ربما أنا فقط؟


دائمًا ما أفضّل let بمتغير مثيل لسببين:

  • المتغيرات مثيل الربيع إلى الوجود عند الإشارة إليها. هذا يعني أنه إذا كان لديك إصبع فاتح تهجئة متغير الحالة ، سيتم إنشاء واحدة جديدة وتهيئتها إلى nil ، والتي يمكن أن تؤدي إلى أخطاء دقيقة وإيجابيات كاذبة. منذ أن NameError طريقة ، ستحصل على NameError عندما NameError ، والتي أجدها مفضلة. فهو يجعل من السهل الحصول على مواصفات refactor ، أيضا.
  • سيتم تشغيل الخط before(:each) قبل كل مثال ، حتى إذا كان المثال لا يستخدم أي من متغيرات الحالة المعرفة في الخطاف. هذه ليست عادة صفقة كبيرة ، ولكن إذا كان إعداد متغير الحالة يستغرق وقتًا طويلاً ، فأنت تهدر الدورات. بالنسبة للأسلوب المحدد بواسطة let ، يتم تشغيل رمز التهيئة فقط إذا كان المثال يستدعي ذلك.
  • يمكنك refactor من متغير محلي في مثال مباشرة في السماح دون تغيير بناء الجملة الرجوع في المثال. إذا كنت refactor إلى متغير مثيل ، يجب عليك تغيير كيفية الرجوع إلى الكائن في المثال (على سبيل المثال إضافة @ ).
  • هذا أمر شخصي نوعًا ما ، ولكن كما أشار مايك لويس ، أعتقد أنه يجعل المواصفات أسهل في القراءة. أنا أحب تنظيم تحديد جميع الأشياء التابعة الخاصة بي مع let والاحتفاظ it كتلة لطيفة وقصيرة.

لقد قمت باستبدال جميع استخدامات متغيرات الحالة في اختبارات rspec الخاصة بي لاستخدام let (). لقد كتبت مثالًا سريعًا لأحد الأصدقاء الذين استخدموه لتدريس فئة Rspec صغيرة: http://ruby-lambda.blogspot.com/2011/02/agile-rspec-with-let.html

كما تقول بعض الإجابات الأخرى هنا ، دع () يتم تقييمها كسولًا ، بحيث يتم تحميل تلك التي تتطلب التحميل فقط. انها جافة المواصفات وجعلها أكثر قابلية للقراءة. لقد قمت في الواقع بنقل رمز Rspec () لاستخدامه في وحدات التحكم الخاصة بي ، في نمط جوهرة الموروثة. http://ruby-lambda.blogspot.com/2010/06/stealing-let-from-rspec.html

جنبا إلى جنب مع التقييم البطيئة ، فإن الميزة الأخرى هي أنه ، جنبا إلى جنب مع ActiveSupport :: قلق ، وتحميل كل شيء في المواصفات / دعم / السلوك ، يمكنك إنشاء الخاصة بك الصغيرة الخاصة DSL محددة للتطبيق الخاص بك. لقد كتبت منها للاختبار ضد موارد Rack و RESTful.

الإستراتيجية التي أستخدمها هي Factory-everything (عبر Machinist + Forgery / Faker). ومع ذلك ، فمن الممكن استخدامه مع ما سبق (: كل) كتل للتحميل المسبق للمصانع لمجموعة كاملة من مجموعات المثال ، مما يسمح بتشغيل المواصفات بشكل أسرع: http://makandra.com/notes/770-taking-advantage-of-rspec-s-let-in-before-blocks


ملاحظة إلى Joseph - إذا كنت تقوم بإنشاء كائنات قاعدة بيانات في before(:all) فلن يتم التقاطها في إحدى المعاملات وكنت أكثر احتمالاً أن تترك محرك البحث في قاعدة بيانات الاختبار الخاصة بك. استخدم before(:each) بدلاً من ذلك.

والسبب الآخر لاستخدام التقييم وتقييمه البطيء هو أنه يمكنك أخذ كائن معقد واختبار القطع الفردية عن طريق تجاوز العوائق في السياقات ، كما هو الحال في هذا المثال المفيد للغاية:

context "foo" do
  let(:params) do
     { :foo => foo,  :bar => "bar" }
  end
  let(:foo) { "foo" }
  it "is set to foo" do
    params[:foo].should eq("foo")
  end
  context "when foo is bar" do
    let(:foo) { "bar" }
    # NOTE we didn't have to redefine params entirely!
    it "is set to bar" do
      params[:foo].should eq("bar")
    end
  end
end




bdd