আপনি একটি নতুন প্রোজেক্ট শুরু করেছেন এবং আপনার কোডের একটি থার্ড-পার্টি সার্ভিসে ডিপেন্ডেন্সি আসেছে। এটি ElasticSearch, Resque, একটি বিলিং প্রোভাইডার, বা শুধু একটি আর্বিট্রারি HTTP API হতে পারে। আপনি একজন ভালো ডেভেলপার, তাই আপনি এই কোডকে ভালোভাবে টেস্ট করতে চান। কিন্তু আপনি কীভাবে সেই কোড টেস্ট করবেন যা আপনার কন্ট্রোলের বাইরে একটি সার্ভিসে রিকোয়েস্ট ফায়ার করে?
আপনি টেস্টগুলো স্কিপ করতে পারেন, কিন্তু আপনি শীঘ্রই একটি শেকি ফাউন্ডেশনের ওপর আরও কোড পাইল করবেন। আনটেস্টেড কোড আরও জটিল কোড আট্রাক্ট করে, এবং আপনি ফাইনালি ফিল করবেন যে কোডটি রিফ্যাক্টর করা খুব ডেঞ্জারাস কারণ আপনার সেফ ফিল করার জন্য টেস্ট কভারেজ নেই। আপনি আপনার ভবিষ্যতের কাজের জন্য একটি স্টেবল ফাউন্ডেশন বিল্ড করতে চান, কিন্তু বদলে আপনি একটি অনমেইনটেইনেবল মেস পেয়ে গেলেন।
এই পরিস্থিতি এড়ানো খুব সহজ যা মনে হয়! কিছু টুল এবং কিছু আপ-ফ্রন্ট এফার্ট দিয়ে, আপনি আপনার টেস্টগুলো আপনার কোড যে সার্ভিসগুলোতে ডিপেন্ড করে সেগুলো থেকে ডিকাপল করতে পারেন, সিম্পলার কোড লিখতে পারেন, এবং আপনি যা লিখেছেন সেটি বাগ ইন্ট্রোডুস ছাড়া উন্নত করার কনফিডেন্স পেতে পারেন। পরবর্তী টেস্টগুলো লিখতে প্রক্রাস্টিনেট করার বদলে, আপনি আপনার কোড এবং বাইরের দুনিয়ার মধ্যে একটি ইন্টারঅ্যাকশন দেখতে পারেন, এবং ঠিক জানতে পারেন কীভাবে সেটির মাঝপথে রাইট জাম্প করতে হয়।
Mocha: দ্রুত এবং গদা আপনা
Mocha আপনার কোড এবং বাইরের দুনিয়ার মাঝপথে ঢুকতে সবচেয়ে সহজ উপায়।
উদাহরণস্বরূপ, বলুন আপনার একটি Cart অবজেক্ট আছে যা চেকআউট হলে ক্রেডিট কার্ড চার্জ ট্রিগার করে। আপনি নিশ্চিত করতে চান যে চার্জ ফেইল হলে কার্টে একটি এরর মেসেজ অ্যাটাচ হয়।
আপনি হয়তো আপনার টেস্টগুলোকে প্রতিবার রান হলে আসলে বিলিং সিস্টেমে হিট করতে দিবেন না। এমনকি আপনি দিলেও, সার্ভিসকে ফেইলিয়ার রিটার্ন করাতে ফোর্স করা কঠিন হতে পারে। Mocha দিয়ে এটি কেমন দেখাবে:
def test_error_message_set_on_charge_failure
cart = Cart.new(items)
cart.stubs(:charge!).returns(false) # mocha in action
cart.checkout!
assert_equal "The credit card could not be charged", cart.credit_card_error
end
Mocha আপনার টেস্টগুলো ফেইলও করাতে পারে যদি মেথডগুলো আপনার এক্সপেক্টেশন অনুযায়ী কল না হয়:
def test_only_bill_once_per_cart
cart = Cart.new(items)
cart.expects(:charge!).once # ডাবল-বিল না, কতবার চেকআউট করলেও
cart.checkout!
cart.checkout!
end
Mocha ব্যবহার করা সিম্পল, কিন্তু অবিশ্বাস্যভাবে হ্যান্ডি হতে পারে। আপনাকে সতর্ক থাকতে হবে যে আপনি শুধু সেই বিহেভিয়ার মক করছেন যা আপনি ঘটতে চান না – খুব বেশি মক করা সহজ এবং রিয়াল বাগ লুকিয়ে ফেলে। আপনি এই অ্যাপ্রোছও ওভারবোর্ডে যেতে চাবেন না: expects এবং stubs দিয়ে ভরা টেস্ট পড়তে এবং চিন্তা করা কঠিন।
Test Fakes: আমার পছন্দের আপনা
আপনি যদি একই অবজেক্টে একই মেথডগুলো বারবার মক বা স্টাব করেন, তবে আপনি আপনার মকগুলোকে ফুল-ফ্লেজড অবজেক্টে প্রোমোট করতে পারেন (কখনও কখনও test fakes বলা হয়), এইভাবে:
def test_billed_full_amount_minus_discount
test_payment_provider = TestPaymentProvider.new # A fake payment provider
cart = Cart.new(items, discount: 30, provider: test_payment_provider)
cart.checkout!
assert_equal items.sum(:&price) * 0.7, test_payment_provider.total_charges
end
Fakes চমৎকার:
-
আপনার ফেক তার ইন্টারনাল স্টেট ট্র্যাক রাখতে পারে
ফেকটি কাস্টম অSSERTION মেসেজ এবং হেল্পার ফাংশন থাকতে পারে যা আপনার টেস্ট লিখাকে সহজ করে, যেমন উপরের উদাহরণে
total_chargesমেথড। -
একটি ফুল-ফ্লেজড অবজেক্ট হলে, আপনি একস্ট্রা এডিটর এবং ল্যাঙ্গুয়েজ সাপোর্ট পান
আপনি যদি সাপোর্ট করা একটি এডিটর ব্যবহার করেন, তবে আপনি অটোকম্প্লিট, ইনলাইন ডকুমেন্টেশন, এবং অন্যান্য জিনিস পাবেন যা Mocha দিয়ে ইন্ডিভিজুয়াল মেথড স্টাব করলে পাবেন না। আপনি আরও ভালো ভ্যালিডেশন, এক্সেপশন হ্যান্ডলিং, এবং যা খুশি সেটি আপনার ফেকতে বিল্ড করতে পারবেন।
-
আপনি যদি ডেভেলপমেন্ট মোডে একটি ফেক ব্যবহার করেন, তবে আপনাকে রিয়াল সার্ভিসের সাথে কানেকশন থাকতে হবে না
আপনি বাসে বসে আপনার অ্যাপ লিখতে পারেন, আপনার ল্যাপটপের ব্যাটারি খাওয়া সার্ভিসের জঙ্গল থাকতে হবে না, এবং আপনি এই ফেক সার্ভিসগুলো সেট আপ করতে পারেন যাতে আপনি সেটআপের ঘোর ছাড়া এজ কেসগুলোর মাধ্যমে কাজ করতে পারেন।
-
এই অবজেক্টগুলো আপনার টেস্টের বাইরেও ব্যবহার করা যায়
এটি হয়তো আমার ফেকের ফেভারিট পার্ট। আপনি একটি লগিং ক্লায়েন্ট থাকতে দিতে পারেন যা একটি থার্ড-পার্টি সার্ভিসে এবং আপনার ফেকেও লগ করছে, যেটি একটি ইন-মেমরি অ্যারে দিয়ে ব্যাকড। আপনি তারপর আপনার সাইটের একটি অ্যাডমিন ভিউতে এই অ্যারের কন্টেন্ট ডাম্প করতে পারেন, যা আপনি যা লগ করছেন সেটি আপনি কি লগ করছেন তা ভেরিফাই করা অনেক সহজ করে দেয়।
আপনি এমন কিছু করতে পারেন:
fake_backend = FakeBackend.new
LoggingService.backends = [RealBackend.new, fake_backend]
LoggingService.debug("TEST MESSAGE PLEASE IGNORE")
fake_backend.messages.first # => [:debug, "TEST MESSAGE PLEASE IGNORE"]
একটি ফেক লিখতে মেথড স্টাব করার চেয়ে বেশি এফার্ট লাগে, কিন্তু প্র্যাকটিসের সাথে এটি এক বা দুই ঘন্টার বেশি লাগা উচিত নয় একটি হেল্পফুল ফেক বিল্ড করতে। আপনি যদি একটি বিল্ড করেন যা অন্যদের উপযোগী হবে, শেয়ার করুন! আমি অনেক আগে resque-unit বানিয়েছিলাম, এবং আজও অনেক লোক সেটি ব্যবহার করে।
তবে আমি এই অবজেক্টগুলো ইনজেক্ট কীভাবে করব?
আপনাকে আপনার টেস্ট হচ্ছে অবজেক্টগুলোকে এই ফেকগুলো থেকে কথা বলতে হবে। সৌভাগ্য, রুবি এত সহজে অবিউজ করা যায় যে ফেক ইনজেক্ট করা সাধারণত কঠিন নয়।
আপনি যদি টেস্ট হচ্ছে অবজেক্টের API কন্ট্রোল করেন, তবে একটি ডিফল্ট প্যারামিটার, একটি অ্যাট্রিবিউট, বা একটি কন্সট্রাক্টর অপশন যোগ করা বেস্ট যেখানে আপনি আপনার ফেক সেট করতে পারেন:
class Card
attr_reader :provider
def initialize(items, options={})
@provider = options.fetch(:provider) { RealProvider.new }
end
end
এটি রিয়াল সার্ভিসে কথা বলার সময় ক্লিন এবং পরে ফ্লেক্সিবিলিটি যোগ করার হুক দেয়।
আপনি যদি অবজেক্ট কন্ট্রোল না করেন বা একস্ট্রা প্যারামিটার যোগ করতে না চান, তবে আপনি সবসময় মনকি প্যাচ করতে পারেন:
# if in test mode
Card.class_eval do
def provider
@provider ||= TestProvider.new
end
end
টেস্টে এটা বদসूरत, কিন্তু ফেক ব্যবহার না করা এনভাॅইরনমেন্টে ক্লিন।
এখনই আপনার নিজস্ব ফেক বিল্ড করা শুরু করুন
ফেক বিল্ড করা প্র্যাকটিসের সাথে সহজ হয়, তাই আপনাকে এখন চেষ্টা করা উচিত:
- একটি টেস্ট খুঁজুন যা একটি এক্সটার্নাল সার্ভিসে কথা বলে। যে টেস্টগুলো ইন্টারনেট ডিসকানেক্ট করলে ফেইল করবে সেগুলো ভালো ক্যান্ডিডেট।
- ফিগার আউট করুন কোন অবজেক্ট আসলে কমিউনিকেশন করে, এবং আপনার কোড সেই অবজেক্টে কী কল করে।
- उस অবজেক্টের ক্লাসের একটি’actually empty ডুপ্লিকেট তৈরি করুন, এবং এটিকে আপনার কলগুলো একটি অ্যারেতে লগ করতে দিন।
- আপনার ফকে একটি মেথড যোগ করুন কল করা লিস্ট রিটার্ন করার জন্য।
- রিয়াল অবজেক্টকে আপনার নতুন ফেক অবজেক্ট দিয়ে রিপ্লেস করুন, এবং আপনার কোড যে কলগুলো করছে সেগুলোর বিপরীতে কিছু অSSERTION লিখুন।
আপনি যদি চেষ্টা করেন, আমাকে জানান কীভাবে গেল!
এই টেকনিকগুলো দিয়ে, আপনি আপনার অ্যাপ্লিকেশন এবং বাইরের দুনিয়ার মাঝপথে সবচেয়ে ক্রেজি ইন্টারঅ্যাকশনগুলো কন্ট্রোল করতে পারবেন খুব দ্রুত। সঠিক জায়গায় একটি সিম্পল স্টাব আপনাকে কনফিডেন্স দিয়ে আপনার ভালো-টেস্টেড কোড শিপ করতে দেবে।