টেস্টিং অধিকাংশ ভালো কাজ করার রেইলস অ্যাপ্লিকেশনের অপরিহার্য অংশ, যেখানে মেইনটেন্যান্স নাইটমার না হয় এবং নতুন ফিচারগুলো নিয়মিত যোগ হয় বা বিদ্যমানগুলো উন্নত হয়। দুর্ভাগ্য থেকে, অনেক অ্যাপ্লিকেশনের জন্য প্রডাকশন এনভায়রনমেন্টই প্রথমবার হয় যেখানে সেগুলো ভারী ওয়ার্কলোড বা σημαντিক ট্রাফিকের আওতাভুক্ত হয়। এটি বোঝা যাচ্ছে কারণ এ ধরনের টেস্টগুলো ব্যয়বহুল।
সৌভাগ্যক্রমে, রেইলসে শুধু ইউনিট, এন্ড-টু-এন্ড, এবং ইন্টিগ্রেশন টেস্টের জন্য নয়, পারফরম্যান্স এবং লোডিং-सम्बन्धিত টেস্টের জন্যও ভালো সাপোর্ট রয়েছে। এই আর্টিকেলে আমি সকল কভার করব এবং কিছু বাস্তব উদাহরণ দেখাব যা আপনাকে বুঝতে সাহায্য করবে কীভাবে আপনার অ্যাপ্লিকেশনের পারফরম্যান্স লেভেল টেস্ট করার টুলগুলো দক্ষতার সাথে ব্যবহার করবেন।
আর্টিকেলটি দুটি সেকশনে বিভক্ত:
সিদ্ধান্তিক (Theoretical) — আমি দেখাবো কেন টেস্টিং জরুরি, আমরা কী কী ধরনের টেস্ট পারফরম করতে পারি, এবং অ্যাপ্লিকেশনে টেস্ট পারফর্ম করার সময় কোন মেট্রিক্সগুলো অত্যন্ত গুরুত্বপূর্ণ
ব্যবহারিক (Practical) — আমরা হাত গোঁড়া করব এবং একটি বাস্তব অ্যাপ্লিকেশনের জন্য টেস্ট লিখব আউটপুট পাওয়ার জন্য
দুই সেকশন পড়ার পর, আপনার টেস্টের বিভিন্ন ধরন এবং কীভাবে আপনার রেইলস অ্যাপ্লিকেশনে সেগুলো পারফর্ম করতে হয় সেটা নিয়ে গভীর বোঝাপড়া হবে। আগ্রহী? তবে চলো টেস্ট সম্পর্কে কয়েকটি সিদ্ধান্তিক কথা থেকে শুরু করি।
সিদ্ধান্তিক দৃষ্টিতে টেস্টিং
টেস্টিং যেকোনো ধরনের অ্যাপ্লিকেশন ডেভেলপমেন্টের অন্তর্নিহিত অংশ হওয়া উচিত। আপনি যদি এখনো টেস্টিং নিয়ে নিশ্চিত ন হন বা কোনো টেস্ট লিখেননি, তবে টেস্টিংর পক্ষে কিছু যুক্তি নিচে দেওয়া হলো:
- কিছু ভাঙায় ভয় ছাড়া পরিবর্তন আনা — এটি টেস্টিং জরুরির প্রধান কারণ। একটি বড় অ্যাপে কাজ করার কাল্পনিক করুন যেখানে প্রতিবার কোনো পরিবর্তন আনার সময় — এমনকি একটি ছোট পরিবর্তন — পুরো অ্যাপে ক্লিক করে ভেরিফাই করতে হয় কিছু ভাঙা নাই কিনা। টেস্ট থাকলে, আপনি শুধু একটা কমান্ড রান করবেন এবং ভেরিফিকেশন প্রসেস স্বয়ংক্রিয় এবং দ্রুত হবে।
সহজ রিফ্যাক্টরিং প্রসেস — আমি উপরে বলেছি নতুন ফিচার যোগ করা বা পরিবর্তন করার সময় টেস্টিং অত্যন্ত জরুরি। টেস্টিং থাকলে, আপনি বিদ্যমান কোড উন্নত করার বিষয়েও বেশি কমফরটেবল महসूस করবেন।
টেস্ট হলো ডকুমেন্টেশনের একটি রূপ — ভালোভাবে লেখা টেস্টগুলো অ্যাপ্লিকেশনের বিভিন্ন ফিচার সেটের জন্য ডকুমেন্টেশন হিসেবে কাজ করতে পারে। সেগুলো শুধু ফিচারটি কী সেটা বর্ণনা করে না, বরং সেটা কীভাবে কাজ করা উচিত সেটাও বলে।
ইমপ্লিমেন্টেশন পুনর্বিবেচনার সুযোগ — আপনি যখন টেস্ট লিখেন, আপনার পায় একবার আবার চিন্তা করার সুযোগ পায় যে আপনি যে পথে কোড ইমপ্লিমেন্ট করতে চাচ্ছেন সেটা সঠিক এবং যুক্তিসঙ্গত কিনা। এছাড়া, আপনি সরাসরি চেক করতে পারেন আপনার কোড আপনার আশা অনুযায়ী কাজ করছে কিনা।
আশা করি উপরের যুক্তিগুলো আপনাকে যেকোনো অ্যাপ ডেভেলপমেন্টের সময় টেস্ট ব্যবহার করতে القা করল। কেন টেস্ট করবেন সেটা জানা অত্যন্ত জরুরি, একই সাথে বিভিন্ন টেস্টের ধরন সম্পর্কে জানাও অত্যন্ত গুরুত্বপূর্ণ।
টেস্টের বিভিন্ন ধরন
তিনটি প্রধান টেস্টের ধরন রয়েছে যেগুলো লিখে আপনি নিশ্চিত করতে পারেন যে আপনার রেইলস অ্যাপ্লিকেশনের পারফরম্যান্স সঠিক এবং ইনফ্রাস্ট্রাকচার ভারী ওয়ার্কলোডের নিচেও ভালো কাজ করছে। সেগুলো হলো:
- লোড টেস্টিং (Load Testing) — এই টেস্টটি এই প্রশ্নের উত্তর দেয়: একটি নির্দিষ্ট সময়ের জন্য সিস্টেম কতগুলো সিমাল্টেনিয়াস ইউজার হ্যান্ডেল করতে পারে। কল্পনা করুন আপনার ওয়েবসাইটে একটি জনপ্রিয় প্রোডাক্ট লঞ্চ করলেন এবং হাজার হাজার ইউজার একই সময়ে অর্ডার দিতে চায়। সঠিক লোড টেস্ট ছাড়া, সবচোয়ে ক্রিটিকাল সময়ে ক্র্যাশের ঝুঁকি রয়েছে।
- স্ট্রেস টেস্টিং (Stress Testing) — এই টেস্টে, আপনি সিস্টেম কত ইউজার হ্যান্ডেল করতে পারে সেটা ভেরিফাই করবেন না, বরং যখন ইউজারের লিমিট হিট হয় তখন সিস্টেম কীভাবে বيهاয়্ভ করে সেটা দেখবেন।
- পারফরম্যান্স টেস্টিং (Performance Testing) — আমি বলব এটি স্ট্রেস এবং লোড টেস্টিংর পেরেন্ট। এ ধরনের টেস্টের প্রাইমারি উদ্দেশ্য হলো একটি নির্দিষ্ট সেট মেট্রিক্স পাওয়া যার বেসিসে আমরা অ্যাপ্লিকেশনের কোড উন্নত করার জন্য কিছু একশন নিতে পারি। আমি সেই মেট্রিক্সগুলো একটু পরে আলোচনা করব।
এই बात들 ধরে, আমরা এখন থিয়োরি পার্টের শেষ ধাপে প্রস্তুত: রেইলস অ্যাপ্লিকেশনে পারফরম্যান্স টেস্টিং করার সময় কোন মেট্রিক্সগুলো অত্যন্ত গুরুত্বপূর্ণ সেটা শিখা। সেটা না জানলে, আমরা টেস্ট আউটপুট সঠিকভাবে ইন্টারপ্রেট করতে পারব না এবং সিদ্ধান্ত নিতে পারব না যে কোড চেঞ্জ করা উচিত কিনা।
গুরুত্বপূর্ণ মেট্রিক্স
আপনি টেস্টিংের জন্য কোন টুল ব্যবহার করছেন তার উপর নির্ভর করে আপনি যে টাইপের মেট্রিক্স পাবেন সেটা আলাদা হতে পারে, কিন্তু সাধারণত আমরা সেগুলো কিছু কমন মেট্রিক্স গ্রুপে বান্ডল করতে পারি:
- রেসপন্স টাইম (Response Time) — রিকোয়েস্ট করা থেকে রেসপন্স ব্রাউজারে রেন্ডার হওয়া পর্যন্তের সময়। এই মেট্রিক্স আমাদের দেখায় ইউজারকে কতক্ষণ অপেক্ষা করতে হয় তার চাওয়া ইনফরমেশন পাওয়ার আগে। ইহাকে কখনও কখনও প্রসেস টাইমও বলা হয়।
- মেমরি ইউজেজ (Memory Usage) — একটি দেয়া রিকোয়েস্টের জন্য খরচ হওয়া মেমরির পরিমাণ। এটি অত্যন্ত গুরুত্বপূর্ণ ইনফরমেশন কারণ এটি আপনাকে সো-cause পয়েন্ট করে দেয় যেখানে আপনি কোড উন্নত করে সিস্টেমকে দ্রুত রেসপন্ড করতে এবং কম রিসোর্স ব্যবহার করতে পারেন।
- অবজেক্ট এলোকেশন (Objects Allocation) — হাই মেমরি এলোকেশন হাই মেমরি ইউজেজ এবং লং রেসপন্স টাইমের কারণ হয়। এই মেট্রিক্স আপনাকে কোডের সঠিক জায়গায় নিয়ে যেতে পারে যেখানে অনেক অবজেক্ট এলোকেট হচ্ছে, যাতে আপনি সেটা অবিলম্বে ইনস্পেক্ট করতে পারেন।
টেস্টিং করার সময় আপনি আরও মেট্রিক্স পেতে পারেন, কিন্তু এই তিনটিই সবচোয়ে গুরুত্বপূর্ণ এবং যেকোনো অ্যাপ্লিকেশন যা আপনি টেস্ট করবেন তার জন্য বৈধ থাকবে। এখন আমরা হাত গোঁড়া করব এবং বাস্তব টেস্ট লিখব।
অনুশীলন (Practice)
আমরা টেস্ট লিখতে পারব না যদি টেস্ট করার জন্য কিছু না থাকে। তাই প্র্যাকটিস পার্টের প্রথম ধাপ হলো একটি সিম্পল রেইলস অ্যাপ্লিকেশন লিখা যেটার জন্য আমরা টেস্ট লিখব।
স্যাম্পল রেইলস অ্যাপ্লিকেশন
আমি Ruby 3.0.1 এবং Rails 6.1.3.1 ব্যবহার করব, তবে আপনি যে ভার্সনে কমফরটেবল সেটা ব্যবহার করতে পারেন। আপনার রুবি এবং রেইলস ইনস্টলড থাকলে, পরবর্তী ধাপ হলো অ্যাপ্লিকেশনের স্কেলেটন তৈরি করা:
rails new simpleapp -d=postgresql
আর্টিকেলের উদ্দেশ্যে, আমি একটি অ্যাপ তৈরি করব যেখানে ইউজারদের লিস্ট তাদের পেটের নামের সাথে দেখানো হবে। এমন কাঠামো আমাদের সহজে N+1 কোয়েরি তৈরি করতে দেবে যা পারফরম্যান্স টেস্ট করার সময় স্পীড এবং অন্যান্য মেট্রিক্সের ওপর পরিবর্তনের প্রভাব দেখতে বেশি মজা দেবে।
মডেল জেনারেট করার আগে, ডাটাবেস তৈরি করি:
cd simpleapp/ bin/rails db:create
এখন, মডেলগুলো জেনারেট করি:
rails g model User name:string rails g model Animal name:string user:references bin/rails db:migrate
User মডেলে একটু আপডেট করে Animal মডেলের সাথে রিলেশনশিপ রিফলেক্ট করি:
class User < ApplicationRecord has_many :animals end
এখন db/seeds.rb ফাইলে কিছু সিড যোগ করি:
people = { 'Tim' => ['Pinky', 'Rick'], 'Martha' => ['Rudolph'], 'Mark' => ['Niki', 'Miki', 'Bella'], 'Tina' => ['Tom', 'Luna'] } people.each_pair do |name, pets| user = User.create(name: name) pets.each do |pet_name| user.animals.create(name: pet_name) end end
এবং ডেটা ডাটাবেসে লোড করি:
bin/rails db:seed
আমি একটি কন্ট্রোলার তৈরি করব ইউজার অ্যাসাইনমেন্টের সাথে, এবং ভিউতে সব ইউজারকে তাদের পেটের নামের সাথে লিস্ট করব। আমি ইচ্ছাকৃতভাবে পারফরম্যান্স সমস্যা সৃষ্টি করার কোড ব্যবহার করছি যাতে আপনি পরে উন্নতির প্রভাব পরিমাপ করতে পারেন।
touch app/controllers/home_controller.rb mkdir app/views/home touch app/views/home/index.html.erb
কন্ট্রোলারটি সিম্পল:
class HomeController < ApplicationController def index @users = User.all end end
ভিউটিও সিম্পল:
<h1>List</h1> <ul> <% @users.each do |user| %> <li><%= user.name %> (<%= user.animals.count %>) <ul> <% user.animals.each do |animal| %> <li><%= animal.name %></li> <% end %> </ul> </li> <% end %> </ul>
শেষ ধাপ: config/routes.rb ফাইল আপডেট করি যাতে রেইলস বুঝতে পারে মেইন URL ভিজিট করলে কী দেখাবে:
Rails.application.routes.draw do root to: 'home#index' end
JMeter দিয়ে লোড টেস্ট
JMeter হলো Apache Software Foundation দ্বারা তৈরি একটি ওপেন-সোর্স সফটওয়্যার, যা ফাংশনাল বিহেভিয়ার লোড টেস্ট করার জন্য ডিজাইন করা। যেহেতু এটি জাভা দিয়ে তৈরি, আপনি যেকোনো অপারেটিং সিস্টেমে ইনস্টল করতে পারেন। ডাউনলোড করুন: https://jmeter.apache.org/download_jmeter.cgi
macOS-এ কাজ করলে, Homebrew দিয়ে সহজে JMeter ইনস্টল করতে পারেন:
brew install jmeter
ইনস্টলেশনের পর, নিচের কমান্ড দিয়ে প্রোগ্রাম চালান:
jmeter
টেস্ট কনফিগার করা
কনফিগারেশন প্রসেস নিচের ধাপগুলো ধারণ করে:
- থ্রেড গ্রুপ যোগ করা — ইউজার সংখ্যা এবং প্রতিটি কতক্ষণ আপনার ওয়েবসাইট ভিজিট করবে সেটা স্পেসিফাই করা
- HTTP রিকোয়েস্ট কনফিগার করা — JMeter যেটা হিট করবে সেই এন্ডপয়েন্ট স্পেসিফাই করা
- আমাদের যেসব মেট্রিক্সে আগ্রহ সেটা সেট করা
আমাদের তৈরি করা সিম্পল অ্যাপের মেইন পেজে একটি সিঙ্গল ইউজার রিকোয়েস্ট সিমুলেট করার জন্য একটি সিম্পল টেস্ট কনফিগারেশন ধাপে ধাপে দেখি।
থ্রেড গ্রুপ যোগ করুন
"Test Plan"-এ রাইট-ক্লিক করে যে মেনু খুলবে সেটা থেকে Add -> Threads (Users) -> Thread Group সিলেক্ট করুন:
ইউজার সংখ্যা এবং অতিরিক্ত অ্যাট্রিবিউটগুলো স্পেসিফাই করুন:
HTTP রিকোয়েস্ট কনফিগার করুন
পূর্বের ধাপে তৈরি করা থ্রেডে রাইট-ক্লিক করুন এবং Add -> Sampler -> HTTP Request সিলেক্ট করুন:
প্রোটোকল, সার্ভার নাম, পোর্ট, এবং রিকোয়েস্টের পাথ কনফিগার করুন:
রেজাল্ট ভিউ স্পেসিফাই করুন
HTTP রিকোয়েস্টে রাইট-ক্লিক করুন এবং Add -> Listener -> View Results Tree সিলেক্ট করুন:
টেস্ট চালান
টেস্ট কনফিগার হয়ে গেল, এখন এটা ট্রিগার করতে পারি। এর জন্য শুধু গ্রিন প্লে বাটনে ক্লিক করুন:
আপনি দেখতে পাচ্ছেন, অ্যাপ্লিকেশন টেস্ট পাস করল, কিন্তু এটা শুধু একটি সিঙ্গল রিকোয়েস্ট ছিল, তাই ফলাফল স্পষ্ট ছিল। এখন আপনি ইউজার সংখ্যা এবং অন্যান্য কনফিগারেশন অপশনসহ এক্সপেরিমেন্ট করতে পারেন দেখতে অ্যাপ্লিকেশন কীভাবে বিহেভ করে। আমার টেস্ট অনুযায়ী, সিম্পল অ্যাপটি کر্যাশ করা শুরু করল যখন প্রায় ২০০ ইউজার একসাথে এক্সেস করল।
পরবর্তী ধাপগুলো
লোড টেস্ট পারফর্ম করার পর, আপনি আপনার অ্যাপ্লিকেশনের পেইন পয়েন্টগুলো জানবেন। ইউজার লিমিট বুঝতে পারলে, আপনি এখন স্ট্রেস টেস্ট পারফর্ম করতে পারেন দেখতে অ্যাপ্লিকেশন কীভাবে বিহেভ করে।
ruby-prof দিয়ে পারফরম্যান্স টেস্ট
পারফরম্যান্স টেস্ট ফিচার রেইলসে ভার্সন ৩ পর্যন্ত বিল্ট-ইন ছিল, তারপর আলাদা জেমে এক্সট্রাক্ট করা হয়েছে: https://github.com/rails/rails-perftest। যেহেতু লেটেস্ট রেইলস ভার্সনের সাথে এটা ব্যবহার করতে আমার কিছু সমস্যা হয়েছিল, আমি এটা এই আর্টিকেলে ইনক্লুড করলাম না। বদলে, আমি ruby-prof লাইব্রেরি ব্যবহার করব যা খুব ভালো কাজ করে।
সহজ উপায়, প্রথম ধাপ হলো আমাদের অ্যাপে জেম যোগ করা:
bundle add ruby-prof
দ্বিতীয় এবং কনফিগারেশন প্রসেসের শেষ ধাপ: config/application.rb আপডেট করুন এবং জেমের জন্য মিডলওয়্যার ব্যবহার করুন যাতে লাইব্রেরি অটোমেটিক্যালি আমাদের রিকোয়েস্টগুলো ইনস্পেক্ট করতে পারে এবং সেগুলোর উপর ভিত্তি করে রিপোর্ট প্রডিউস করতে পারে:
module Simpleapp class Application < Rails::Application config.middleware.use Rack::RubyProf, :path => './tmp/profile' end end
এখন অ্যাপ এক্সেস করুন, এবং আপনি প্রতিবার রিকোয়েস্ট পারফর্ম করলে জেম একটি নতুন রিপোর্ট জেনারেট করবে। দেখতে এমন:
আপনি কনফিগার করা পাথে এটা পাবেন, আমাদের কেসে tmp/profile। দ্বিতীয় রিপোর্টও জেনারেট হয়, যা কল স্ট্যাক দেখায়, যা রেইলস অ্যাপ্লিকেশনে পারফরম্যান্স ইস্যু ডিবাগ করার সময় খুব হেল্পফুল।
মনে রাখবেন: cache_classes এবং cache_template_loading সেটিংস true সেট করলে অ্যাপ স্লো হবে এবং অ্যাপ্লিকেশন মেট্রিক্স ওভারওয়েল্ম হবে কারণ রেইলস প্রয়োজনীয় ফাইলগুলো লোড করার চেষ্টা করবে।
সারসংক্ষেপ
টেস্টিং প্রতিটি ডেভেলপমেন্ট প্রসেসের অপরিহার্য অংশ। কোড আমাদের চাওয়া অনুযায়ী বিহেভ করছে কিনা চেক করা उतনোই গুরুত্বপূর্ণ যতো আমাদের সমাধানগুলো ভালো পারফরম্যান্স দিচ্ছে কিনা ভেরিফাই করা। টেস্ট বাদ দেওয়া\Appের পারফরম্যান্স এবং ইউজারদের আস্থা উভয়ের ওপর গम्भীর প্রভাব ফেলে। সৌভাগ্যক্রমে, টেস্টিং তত কঠিন নয়।
এই আর্টিকেলে আমরা নিচের গুরুত্বপূর্ণ দিকগুলো কভার করেছি:
- কেন আপনাকে আপনার কোড টেস্ট করা উচিত
- পারফরম্যান্স টেস্টের বিভিন্ন ধরন
- আপনার রেইলস অ্যাপের পারফরম্যান্স টেস্ট করার পদ্ধতি
আশা করি আপনি এখন আরও নিশ্চিত হয়েছেন কেন টেস্ট লিখা গুরুত্বপূর্ণ, কারণ আপনি জানেন কেন এবং কীভাবে।
আপনি যদি আপনার অ্যাপের পারফরম্যান্স শুধু লোকালি নয়, বরং প্রডাকশন বা স্টেজিং এনভায়রনমেন্টেও মোনিটর করতে চান, তবে AppSignal চেক আউট করুন।
P.S. Ruby Magic পোস্টগুলো প্রেস থেকে বের होते ही পেতে চাইলে, আমাদের Ruby Magic নিউজলেটার সাবস্ক্রাইব করুন এবং কখনো একক পোস্ট মিস করবেন না!