টেস্ট জেনারেটর হলো ট্র্যাক-ভিত্তিক একটি সফটওয়্যার, যা স্বয়ংক্রিয়ভাবে একটি প্র্যাকটিস অনুশীলনীর টেস্ট তৈরি করে। এটি অনুশীলনীর JSON টেস্ট কেসগুলোকে ট্র্যাকের ভাষার টেস্টে রূপান্তর করে এই কাজটি করে।
একটি টেস্ট জেনারেটর থাকার কিছু সুবিধা হলো:
সাধারণভাবে, একটি টেস্ট জেনারেটর চালানো হয় দুটি কাজের যেকোনো একটির জন্য:
নতুন অনুশীলনীর জন্য একটি টেস্ট জেনারেটর যোগ করলে তার টেস্ট ফাইল(গুলো) তৈরি করা যায়। টেস্ট জেনারেটরটি আগেই তৈরি করা থাকলে, নতুন অনুশীলনীর টেস্ট তৈরি করা শূন্য থেকে লেখার চেয়ে (অনেক) কম পরিশ্রমের কাজ হবে।
একটি অনুশীলনীর টেস্ট জেনারেটর হয়ে গেলে আপনি সেটি আবার চালিয়ে অনুশীলনীটিকে তার সর্বশেষ ক্যানোনিকাল ডেটার সাথে হালনাগাদ/সিঙ্ক করতে পারেন। নিয়মিত এটি করার পরামর্শ দিই, যাতে দেখা যায় হালনাগাদ করা দরকার এমন সমস্যাযুক্ত টেস্ট কেস আছে কি না, বা আপনি যুক্ত করতে চান এমন নতুন টেস্ট আছে কি না।
কোনো অনুশীলনীর জন্য একটি টেস্ট জেনারেটর বাস্তবায়ন করার সময় দুটি সম্ভাব্য শুরুর বিন্দু থাকতে পারে:
বিদ্যমান টেস্ট থাকলে, টেস্ট জেনারেটরটি এমনভাবে বাস্তবায়ন করুন যাতে এটি যে টেস্টগুলো তৈরি করে সেগুলো বিদ্যমান সলিউশনগুলো নষ্ট না করে।
মোটামুটি বলতে গেলে, টেস্ট ফাইল তৈরি করা হয় দুটি উপায়ে:
আমাদের অভিজ্ঞতায়, কোড-ভিত্তিক পদ্ধতিতে টেস্ট জেনারেটরের কোড বেশ জটিল হয়ে যায়, অন্যদিকে টেমপ্লেট-ভিত্তিক পদ্ধতি সরল হয়।
আমরা নিম্নলিখিত ধারাবাহিকতাটি সুপারিশ করি:
tests.toml ফাইল-এ include = false হিসেবে চিহ্নিত টেস্ট কেসগুলো বাদ দিনএই ব্যবস্থার মূল সুবিধা হলো প্রতিটি অনুশীলনীর নিজস্ব টেমপ্লেট থাকে, যা:
টেস্ট জেনারেটর ডিজাইন করার সময় চেষ্টা করুন:
টেস্ট জেনারেটর সাধারণত (বেশিরভাগ ক্ষেত্রে) ট্র্যাকের ভাষায় লেখা হয়।
অন্য ভাষা ব্যবহার করতে আপনি স্বাধীন, তবে প্রতিটি অতিরিক্ত ভাষা ট্র্যাক মেইনটেইন করা বা এতে কন্ট্রিবিউট করা আরও কঠিন করে তোলে। তাই আমরা যেখানে সম্ভব ট্র্যাকের ভাষা ব্যবহার করার পরামর্শ দিই, কারণ এতে মেইনটেইন বা কন্ট্রিবিউট করা সহজ হয়।
আপনার ট্র্যাকের কোড ফরম্যাট করার টুল থাকলে, টেমপ্লেট রেন্ডার করার পরে একটি পোস্ট-প্রসেসিং ধাপ হিসেবে এটি চালানোর কথা ভাবতে পারেন।
টেস্ট জেনারেটর যে মূল ডেটা নিয়ে কাজ করে তা হলো একটি অনুশীলনীর canonical-data.json ফাইল।
এই ফাইলটি exercism/problem-specifications রিপোতে সংজ্ঞায়িত, যা Exercism-এর অনেক অনুশীলনীর জন্য শেয়ার করা মেটাডেটা নির্ধারণ করে।
সব অনুশীলনীর canonical-data.json ফাইল থাকে না!
যেগুলোতে থাকে না, সেগুলোর টেস্ট আপনাকে নিজ হাতে তৈরি করতে হবে, কারণ টেস্ট জেনারেটর কাজ করার জন্য কোনো ডেটা থাকবে না।
ক্যানোনিকাল ডেটা একটি JSON অবজেক্টে সংজ্ঞায়িত।
এই অবজেক্টে একটি "cases" ফিল্ড থাকে, যাতে টেস্ট কেসগুলো থাকে।
এই টেস্ট কেসগুলো (সাধারণত) আপনার ট্র্যাকের টেস্টের সাথে এক-এক করে মিলে যায়।
প্রতিটি টেস্ট কেসে কয়েকটি প্রপার্টি থাকে, যার মধ্যে description, property, input মান এবং expected মান সবচেয়ে গুরুত্বপূর্ণ। এখানে leap অনুশীলনীর canonical-data.json ফাইলের একটি (আংশিক) উদাহরণ দেওয়া হলো:
{
"exercise": "leap",
"cases": [
{
"uuid": "6466b30d-519c-438e-935d-388224ab5223",
"description": "year not divisible by 4 in common year",
"property": "leapYear",
"input": {
"year": 2015
},
"expected": false
},
{
"uuid": "4fe9b84c-8e65-489e-970b-856d60b8b78e",
"description": "year divisible by 4, not divisible by 100 in leap year",
"property": "leapYear",
"input": {
"year": 1996
},
"expected": true
}
]
}
টেস্ট জেনারেটরের মূল দায়িত্ব এই JSON ডেটাকে ট্র্যাক-নির্দিষ্ট টেস্টে রূপান্তর করা। উপরের JSON-টি কীভাবে Nim টেস্ট কোডে রূপান্তরিত হতে পারে, তা এখানে দেখানো হলো:
import unittest
import leap
suite "Leap":
test "year not divisible by 4 in common year":
check isLeapYear(2015) == false
test "year divisible by 4, not divisible by 100 in leap year":
check isLeapYear(1996) == true
canonical-data.json ফাইলের গঠন ভালোভাবে নথিভুক্ত এবং এর একটি JSON স্কিমা সংজ্ঞাও আছে।
কিছু অনুশীলনী তাদের ক্যানোনিকাল ডেটায় নেস্টিং ব্যবহার করে।
এর অর্থ হলো cases অ্যারের প্রতিটি এলিমেন্ট হয়তো:
কোনো এলিমেন্টের ধরন শনাক্ত করতে পারেন সেই এলিমেন্ট-ধরনের জন্য একান্তভাবে থাকা ফিল্ডগুলো আছে কি না দেখে।
সম্ভবত এটির সবচেয়ে ভালো উপায় হলো "cases" কী (key) ব্যবহার করা, যা শুধু টেস্ট কেস গ্রুপেই থাকে।
নেস্টেড টেস্ট কেসের একটি উদাহরণ এখানে:
{
"cases": [
{
"uuid": "e9c93a78-c536-4750-a336-94583d23fafa",
"description": "data is retained",
"property": "data",
"input": {
"treeData": ["4"]
},
"expected": {
"data": "4",
"left": null,
"right": null
}
},
{
"description": "insert data at proper node",
"cases": [
{
"uuid": "7a95c9e8-69f6-476a-b0c4-4170cb3f7c91",
"description": "smaller number at left node",
"property": "data",
"input": {
"treeData": ["4", "2"]
},
"expected": {
"data": "4",
"left": {
"data": "2",
"left": null,
"right": null
},
"right": null
}
}
]
}
]
}
আপনার ট্র্যাক যদি গ্রুপ করা টেস্ট সমর্থন না করে, তাহলে আপনাকে করতে হবে:
cases হায়ারার্কি ট্রাভার্স/ফ্ল্যাটেন করা, যাতে শেষে শুধু সবচেয়ে ভেতরের (লিফ) টেস্ট কেসগুলো থাকেinput ও expected টেস্ট কেস কী (key)গুলোর বিষয়বস্তু ব্যাপকভাবে ভিন্ন হয়।
বেশিরভাগ ক্ষেত্রে এগুলো স্কেলার মান (যেমন সংখ্যা, বুলিয়ান বা স্ট্রিং) বা সরল অবজেক্ট হয়।
তবে মাঝেমধ্যে আরও জটিল মানও পাবেন, যেগুলোর জন্য সম্ভবত একটু প্রি-প্রসেসিং লাগবে, যেমন সিউডো কোডে ল্যাম্বডা, শিক্ষার্থীদের কোডের ওপর চালানোর জন্য অপারেশনের তালিকা, ইত্যাদি।
টেস্ট কেসে একটি ঐচ্ছিক scenarios ফিল্ড থাকে।
এই ফিল্ডটি টেস্ট জেনারেটর নির্দিষ্ট কিছু টেস্ট কেসকে বিশেষভাবে সামলাতে ব্যবহার করতে পারে।
সবচেয়ে কমন ব্যবহারের ক্ষেত্র হলো কিছু ধরনের টেস্ট বাদ দেওয়া, যেমন "unicode" সিনারিওর টেস্ট, কারণ আপনার ট্র্যাকের ভাষা হয়তো Unicode সমর্থন করে না।
সিনারিওগুলোর সম্পূর্ণ তালিকা এখানে পাওয়া যাবে।
canonical-data.json ফাইলগুলো পড়ার কয়েকটি উপায় আছে:
problem-specifications রিপো থেকে এগুলো আনা (যেমন https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/leap/canonical-data.json)।problem-specifications রিপোকে ট্র্যাক রিপোতে একটি Git সাবমডিউল হিসেবে যোগ করা।configlet ক্যাশ থেকে এগুলো পড়া।
অবস্থানটি ব্যবহারকারীর সিস্টেমের ওপর নির্ভর করে, তবে প্রোগ্রামের মাধ্যমে অবস্থানটি বের করতে আপনি configlet info -o -v d | head -1 | cut -d " " -f 5 ব্যবহার করতে পারেন।আপনার ট্র্যাক যদি কিছু অতিরিক্ত, ট্র্যাক-নির্দিষ্ট টেস্ট কেস যোগ করতে চায় (যা ক্যানোনিকাল ডেটায় পাওয়া যায় না), তার একটি উপায় হলো একটি additional-test-cases.json ফাইল তৈরি করা, যা টেস্ট জেনারেটর পরে রেন্ডারিংয়ের জন্য টেমপ্লেটে পাঠানোর আগে canonical-data.json ফাইলের সাথে মার্জ করতে পারে।
ব্যবহার করার টেমপ্লেট ইঞ্জিন সম্ভবত ট্র্যাক-নির্দিষ্ট হবে। আদর্শভাবে আপনি চাইবেন আপনার টেমপ্লেটগুলো যতটা সম্ভব সরল হোক, তাই কোড ডুপ্লিকেশন ইত্যাদি নিয়ে চিন্তা করবেন না।
টেমপ্লেটগুলো তাদের ডেটা পায় টেস্ট জেনারেটরের কাছ থেকে, যা সেগুলো রেন্ডার করার জন্য ডেটার ওপর ইটারেশন করে।
টেমপ্লেটগুলো সরল রাখতে সাহায্য করার জন্য টেস্ট জেনারেটরের দিকে একটু প্রি-প্রসেসিং করা কাজে লাগতে পারে, অথবা আপনার টেমপ্লেট যেসব এক্সটেনশন ব্যবস্থা সমর্থন করে সেগুলো, যেমন কিছু "ফিল্টার", সংজ্ঞায়িত করা যেতে পারে।
configlet হলো ট্র্যাক মেইনটেইন করার প্রধান টুল, যা ব্যবহার করা যায়:
bin/configlet create --practice-exercise <slug> চালানtests.toml ফাইল সিঙ্ক করতে: bin/configlet sync --tests --update --exercise <slug> চালানএ কারণে configlet টেস্ট জেনারেটরের সাথে মিলিয়ে ব্যবহার করার জন্য দারুণ একটি টুল, যা সত্যিই শক্তিশালী কিছু ওয়ার্কফ্লো তৈরি করতে পারে।
আপনি চাইবেন টেস্ট জেনারেটর ব্যবহার করা যেন সহজ এবং শক্তিশালী হয়। এর জন্য আমরা এক বা একাধিক স্ক্রিপ্ট ফাইল তৈরির পরামর্শ দিই।
আপনার ট্র্যাকের জন্য যে স্ক্রিপ্ট ফাইল ফরম্যাট সবচেয়ে ভালো মানায়, তা বেছে নিতে আপনি স্বাধীন। শেল স্ক্রিপ্ট ও PowerShell স্ক্রিপ্ট কমন এমন দুটি অপশন, যেগুলো দুটোই ভালো কাজ করে।
দ্রুত একটি নতুন অনুশীলনী স্ক্যাফোল্ড করতে configlet ও একটি টেস্ট জেনারেটর একসাথে ব্যবহার করা একটি শেল স্ক্রিপ্টের উদাহরণ এখানে:
bin/fetch-configlet
bin/configlet create --practice-exercise <slug>
path/to/test-generator <slug>
টেস্ট জেনারেটর তৈরি শুরু করার আগে, অন্য ট্র্যাকগুলো কীভাবে এগুলো বাস্তবায়ন করেছে তার একটি ধারণা পেতে আমরা কয়েকটি বিদ্যমান টেস্ট জেনারেটর দেখে নেওয়ার পরামর্শ দিই:
কোনো প্রশ্ন থাকলে তা জিজ্ঞাসা করার সেরা জায়গা হলো ফোরাম। Rust নিয়ে এবং JavaScript টেস্ট জেনারেটর নিয়ে হওয়া ফোরাম আলোচনাগুলোও সহায়ক হতে পারে।
আমরা একটি মিনিমাম ভায়েবল প্রোডাক্ট দিয়ে শুরু করে ধাপে ধাপে টেস্ট জেনারেটর তৈরির পরামর্শ দিই।
একেবারে ন্যূনতম একটি সংস্করণ একটি অনুশীলনীর canonical-data.json পড়বে আর সেই ডেটা সরাসরি টেমপ্লেটে পাঠাবে।
শুরুতে একটি মাত্র অনুশীলনীতে মনোযোগ দিন, বরং leap-এর মতো সরল একটি অনুশীলনীতে।
সেটি কাজ করতে শুরু করলেই ধীরে ধীরে আরও অনুশীলনী যোগ করুন।
আর টেস্ট জেনারেটরকে যতটা সরল রাখা যায়, ততটাই সরল রাখার চেষ্টা করুন।
আদর্শভাবে একজন কন্ট্রিবিউটর টেস্ট জেনারেটর ভেতরে কীভাবে কাজ করে তা না বুঝেই একটি বিদ্যমান টেমপ্লেট পেস্ট/সংশোধন করতে পারবেন।
টেস্ট জেনারেটর কীভাবে ব্যবহার করবেন বা এতে কন্ট্রিবিউট করবেন তা ট্র্যাক-নির্দিষ্ট।
নির্দেশনা খুঁজুন ট্র্যাকের README.md, CONTRIBUTING.md অথবা টেস্ট জেনারেটর কোডের ডিরেক্টরিতে।