টেস্ট রানার ইন্টারফেস


টেস্ট রানারের একটিই দায়িত্ব: একটি সলিউশন নিয়ে তার সব টেস্ট চালানো এবং একটি মানসম্মত আউটপুট ফেরত দেওয়া। Exercism ওয়েবসাইটের সাথে সব ধরনের যোগাযোগ স্বয়ংক্রিয়ভাবে সামলানো হয় এবং তা এই স্পেকের অংশ নয়।

এক্সিকিউশন

  • একটি টেস্ট রানারের একটি এক্সিকিউটেবল স্ক্রিপ্ট থাকা উচিত। আরও তথ্য পাবেন docker.md ফাইলে।
  • স্ক্রিপ্টটি তিনটি প্যারামিটার পাবে:
    • অনুশীলনীর স্লাগ (যেমন two-fer)।
    • সাবমিট করা সলিউশন ফাইল এবং অনুশীলনীর অন্য যেকোনো ফাইল ধারণ করা একটি ইনপুট ডিরেক্টরির পথ (শেষে একটি স্ল্যাশ সহ)। এই ডিরেক্টরিটিকে রিড-অনলি হিসেবে ধরা উচিত। প্রযুক্তিগতভাবে এতে লেখা সম্ভব, তবে টেম্পোরারি ফাইলের জন্য (যেমন সোর্স কম্পাইল করার জন্য) /tmp ব্যবহার করা ভালো।
    • একটি আউটপুট ডিরেক্টরির পথ (শেষে একটি স্ল্যাশ সহ)। এই ডিরেক্টরিতে লেখা যায়।
  • স্ক্রিপ্টটিকে আউটপুট ডিরেক্টরিতে একটি results.json ফাইল লিখতে হবে।
  • সফলভাবে রান হলে, টেস্টের অবস্থা যাই হোক না কেন, রানারকে অবশ্যই 0 এক্সিট কোড নিয়ে বেরিয়ে আসতে হবে।

অনুমোদিত রান সময়

টেস্ট রানার প্রতি সলিউশনের জন্য ২০ সেকেন্ডের একটি উইন্ডোতে 100% CPU এবং 3GB মেমোরি পায়। ২০ সেকেন্ড পর প্রসেসটি থামিয়ে দেওয়া হয় এবং একটি টাইম-আউট রিপোর্ট করা হয়।

Note

টাইম-আউটের সম্ভাবনা কমাতে আমরা দৃঢ়ভাবে আমাদের পারফরম্যান্স বেস্ট প্র্যাকটিস ডকুমেন্ট অনুসরণ করার পরামর্শ দিই।

আউটপুট ফরম্যাট

results.json ফাইলে নিচের ফিল্ডগুলো সমর্থিত:

টপ লেভেল

ভার্সন

কী: version, টাইপ: number, উপস্থিতি: আবশ্যক

ভার্সন: 1, 2, 3

এই ফাইলটি যে স্পেক ভার্সনের সাথে সঙ্গতিপূর্ণ:

  • 1: যেসব ট্র্যাকের টেস্ট রানার আলাদা আলাদা টেস্টের তথ্য দিতে পারে না, তাদের জন্য।
  • 2: যেসব ট্র্যাকের টেস্ট রানার আলাদা আলাদা টেস্টের তথ্য আউটপুট করতে পারে, তাদের জন্য। কনসেপ্ট অনুশীলনী আছে এমন ট্র্যাকের জন্য ন্যূনতম প্রয়োজনীয় ভার্সন।
  • 3: যেসব ট্র্যাকের টেস্ট রানার আলাদা আলাদা টেস্টকে একটি টাস্কের সাথে লিংক করতে পারে, তাদের জন্য।

স্টেটাস

কী: status, টাইপ: string, উপস্থিতি: আবশ্যক

ভার্সন: 1, 2, 3

নিচের সামগ্রিক স্টেটাসগুলো বৈধ:

  • pass: সব টেস্ট পাস করেছে
  • fail: অন্তত একটি টেস্টের স্টেটাস fail বা error
  • error: কোনো টেস্ট রান করা হয়নি (সাধারণত এর অর্থ একটি কম্পাইল এরর বা একটি সিনট্যাক্স এরর)

error স্টেটাস কেবল তখনই ব্যবহার করা উচিত যদি সব টেস্টই এরর দেয়। কম্পাইল করা ভাষার ক্ষেত্রে এটি সাধারণত কোড কম্পাইল করতে না পারার ফলাফল। ইন্টারপ্রেট করা ভাষার ক্ষেত্রে এটি একটি রানটাইম এরর, যেমন একটি সিনট্যাক্স এরর যা ফাইলটি পার্স হতে বাধা দেয়।

মেসেজ

কী: message, টাইপ: string, উপস্থিতি: আবশ্যক যদি status = error, অথবা যখন status = fail এবং version = 1

ভার্সন: 1, 2, 3

যেখানে স্টেটাস error (কোনো টেস্ট সঠিকভাবে রান হয়নি), সেখানে টপ লেভেল message কী দিতে হবে। এটি ব্যবহারকারীর কাছে ঘটা এররটি তুলে ধরবে। যেহেতু নিজেদের সমস্যা ডিবাগ করার জন্য ব্যবহারকারী যে একমাত্র তথ্য পাবেন তা-ই এটি, তাই এটি যতটা সম্ভব স্পষ্ট হতে হবে:

  • পথগুলোকে /full/path/to-এর বদলে <solution-dir>/relative/path-এর মতো সরল করুন, কারণ সেটিতে সহায়ক নয় এমন ECR-নির্দিষ্ট তথ্য থাকবে
  • সম্ভব বা প্রযোজ্য হলে, ব্যবহারকারীর কোড নয় এমন স্ট্যাকগুলো সংকুচিত করুন
  • প্রসঙ্গ ছাড়া (অর্থাৎ এরর মেসেজ ছাড়া) কখনো কল স্ট্যাক দেখাবেন না
  • সম্ভব হলে এরর মেসেজ বদলাবেন না, কারণ তাহলে এররটি খোঁজা সহজ হবে

Ruby-তে সিনট্যাক্স এররের ক্ষেত্রে আমরা রানটাইম এরর এবং স্ট্যাক ট্রেস দিই। কম্পাইল করা ভাষায় কম্পাইলেশন এরর দেওয়া উচিত।

টপ লেভেল message মান ৬৫৫৩৫ অক্ষরে সীমাবদ্ধ। মানটিতে মাল্টিবাইট ক্যারেক্টার থাকলে কার্যকর সর্বোচ্চ দৈর্ঘ্য তার চেয়ে কম হয়।

স্টেটাস error না হলে হয় মানটি null সেট করুন, নয়তো কীটি সম্পূর্ণ বাদ দিন।

টেস্ট

কী: tests, টাইপ: array, উপস্থিতি: আবশ্যক যদি status = fail বা status = pass

ভার্সন: 2, 3

এটি টেস্ট ফলাফলের একটি অ্যারে, যা নিচের "প্রতি-টেস্ট" অংশে বর্ণিত।

টেস্টগুলো অবশ্যই টেস্ট ফাইলে যে ক্রমে নির্দিষ্ট করা আছে, সেই ক্রমেই ফেরত দিতে হবে। যে ভাষাগুলো টেস্ট এলোমেলো ক্রমে চালায়, তাদের ক্ষেত্রে এর অর্থ হতে পারে টেস্ট ফাইলে নির্দিষ্ট ক্রম অনুযায়ী ফলাফলগুলো পুনরায় সাজানো।

এর যুক্তি হলো শিক্ষার্থীদের কেবল প্রথম ব্যর্থতাটিই দেখানো হয়, তাই সঠিক ব্যর্থতাটি দেখানো গুরুত্বপূর্ণ। কারণ টেস্ট ফাইলে টেস্টগুলো সাধারণত TDD পদ্ধতিতে সাজানো থাকে, এবং যেহেতু প্র্যাকটিস অনুশীলনীতে শিক্ষার্থীরা এডিটরে টেস্ট ফাইলটি দেখে, তাই ফলাফলগুলোকে টেস্ট ফাইলের সাথে মিল রাখা অত্যন্ত জরুরি।

প্রতি-টেস্ট

নাম

কী: name, টাইপ: string, উপস্থিতি: আবশ্যক

ভার্সন: 2, 3

এটি মানুষের পড়ার উপযোগী ফরম্যাটে টেস্টের নাম।

টেস্ট কোড

কী: test_code, টাইপ: string, উপস্থিতি: আবশ্যক যদি অনুশীলনী কনসেপ্ট অনুশীলনী হয়

ভার্সন: 2, 3

কনসেপ্ট অনুশীলনীর জন্য এটি অবশ্যই থাকতে হবে এবং প্র্যাকটিস অনুশীলনীর জন্য থাকা উচিত। এই শর্তের পার্থক্যের কারণ হলো কনসেপ্ট অনুশীলনীতে শিক্ষার্থীদের টেস্ট দেখানো হয় না, তাই test_code না দেখালে অনুশীলনী সমাধান করা অসম্ভব হতে পারে, অথচ প্র্যাকটিস অনুশীলনীতে টেস্ট দেখানো হয়।

এটি যে কমান্ডটি টেস্ট করা হচ্ছে তার মূল অংশ। উদাহরণস্বরূপ, নিচের Ruby টেস্টটি:

def test_duplicate_items_uniqs_list
  cart = ShoppingCart.new
  cart.add(:STARIC)
  cart.add(:MEDNEW)
  cart.add(:MEDNEW)
  assert_equal 'Newspaper, Rice', cart.items_list
end

এর ফলে test_code মান হওয়া উচিত:

"cart = ShoppingCart.new
cart.add(:STARIC)
cart.add(:MEDNEW)
cart.add(:MEDNEW)
assert_equal 'Newspaper, Rice', cart.items_list"

(JSON বৈধ করতে লাইনব্রেকগুলো \n দিয়ে প্রতিস্থাপিত)।

স্টেটাস

কী: status, টাইপ: string, উপস্থিতি: আবশ্যক

ভার্সন: 2, 3

নিচের প্রতি-টেস্ট স্টেটাসগুলো বৈধ:

  • pass: টেস্টটি পাস করেছে
  • fail: টেস্টটি ব্যর্থ হয়েছে
  • error: টেস্টটি এরর দিয়েছে, অর্থাৎ এটি কোনো মান রিটার্ন করেনি

মেসেজ

কী: message, টাইপ: string, উপস্থিতি: আবশ্যক যদি status হয় fail বা error

ভার্সন: 2, 3

যে টেস্টের status fail বা error, তার ফলাফল ফেরত দিতে প্রতি-টেস্ট message কী ব্যবহার করা হয়। এটি যতটা সম্ভব মানুষের পড়ার উপযোগী হওয়া উচিত। শিক্ষার্থীর টেস্ট পাস না করলে এখানে যা লেখা আছে তা তাদের দেখানো হবে। কোনো টেস্ট ব্যর্থতার মেসেজ বা এরর মেসেজ না থাকলে হয় মানটি null সেট করুন, নয়তো কীটি সম্পূর্ণ বাদ দিন। এখানে টেস্ট স্যুটের আউটপুট দেওয়াও অনুমোদিত। message মানের দৈর্ঘ্যের কোনো সীমা নেই।

আউটপুট

কী: output, টাইপ: string, উপস্থিতি: ঐচ্ছিক

ভার্সন: 2, 3

ব্যবহারকারী কোনো টেস্টের জন্য সচেতনভাবে যা আউটপুট করে, তা সংরক্ষণ ও আউটপুট করতে প্রতি-টেস্ট output কী ব্যবহার করা উচিত।

  • ব্যবহারকারীর আউটপুট উৎপন্ন করে এমন সব টেস্ট ফলাফলের সাথে এটি যুক্ত করা উচিত।
  • কেবল ব্যবহারকারীর হাতে আউটপুট করা কনটেন্টই দেখানো উচিত, টেস্ট-রানারের স্বয়ংক্রিয় আউটপুট নয়।
  • আপনি হয় সাধারণ উপায়ে আউটপুট হওয়া কনটেন্ট ক্যাপচার করতে পারেন (যেমন Ruby-তে puts, Python-এ print বা C#-এ Debug.WriteLine), নয়তো এমন একটি মেথড দিতে পারেন যা ব্যবহারকারী ব্যবহার করতে পারেন (যেমন Ruby টেস্ট রানার ব্যবহারকারীকে একটি গ্লোবালি উপলভ্য debug মেথড দেয় যা তারা ব্যবহার করতে পারেন, যার বৈশিষ্ট্য সাধারণ puts মেথডের মতোই)।
  • আউটপুট অবশ্যই ৫০০ অক্ষরে সীমাবদ্ধ হতে হবে। এই পরিস্থিতিতে "আউটপুট কেটে দেওয়া হয়েছে। অনুগ্রহ করে ৫০০ অক্ষরে সীমাবদ্ধ রাখুন" বার্তা দিয়ে কেটে দেওয়া অথবা একটি এরর ফেরত দেওয়া, দুটোই গ্রহণযোগ্য।

টাস্ক আইডি

কী: task_id, টাইপ: number, উপস্থিতি: ঐচ্ছিক

ভার্সন: 3

টাস্কের আইডি দিয়ে একটি টেস্টকে নির্দিষ্ট একটি টাস্কের সাথে লিংক করুন, যা টাস্ক শিরোনামের শুরুতে ব্যবহৃত সংখ্যা। কেবল তখনই একটি টেস্টকে একটি টাস্কের সাথে লিংক করুন যদি তা সঠিকভাবে একটি টাস্কের সাথে লিংক করা যায়।

এই মুহূর্তে কেবল কনসেপ্ট অনুশীলনীতেই সুনির্দিষ্ট টাস্ক আছে যেগুলোর সাথে আপনি টেস্ট লিংক করতে পারেন, তবে ভবিষ্যতে এটি বদলাতে পারে।

উদাহরণস্বরূপ, নিচের instructions.md ফাইলটি দেখুন:

# Instructions

You're going to write some code to help Lucian cook an exquisite lasagna from his favorite cook book.

## 1. Define the expected oven time in minutes

...

## 2. Calculate the remaining oven time in minutes

...

এই নির্দেশনাগুলো দুটি টাস্ক সংজ্ঞায়িত করেছে:

  1. Define the expected oven time in minutes
  2. Calculate the remaining oven time in minutes

তাহলে results.json ফাইলে এমন একটি এন্ট্রি থাকতে পারে:

{
  "name": "Expected oven time in minutes",
  "status": "pass",
  "task_id": 1,
  "test_code": "Assert.Equal(40, Lasagna.ExpectedMinutesInOven());"
}

এই টেস্টটি এখন প্রথম টাস্কের সাথে লিংক করা হয়েছে: "Define the expected oven time in minutes"। লক্ষ্য করুন যে নামটি টাস্কের বর্ণনার সাথে মিলতে হবে না।

ট্র্যাকগুলো বিভিন্নভাবে এটি বাস্তবায়ন করতে পারে:

  • টেস্ট ফাইলের ভেতরে টেস্টে মেটাডেটা যোগ করা (যেমন অ্যাট্রিবিউট/অ্যানোটেশন/কমেন্ট ব্যবহার করে) এবং টেস্ট চালানোর সময় টেস্ট রানারকে এই মেটাডেটা পড়তে দেওয়া।
  • টেস্টের নাম ও টাস্ক আইডির ম্যাপিং একটি আলাদা ফাইলে রাখা (যেমন অনুশীলনীর .meta/config.json ফাইল) এবং এই তথ্য তৈরি হওয়া results.json ফাইলে একত্র করা।

উদাহরণ

বিভিন্ন ভার্সনের জন্য একটি বৈধ results.json ফাইল কেমন দেখতে হতে পারে তার উদাহরণ এগুলো:

v1 উদাহরণ

{
  "version": 1,
  "status": "fail",
  "message": "Failed: test_answer\nExpected: 42, actual: 3"
}

v2 উদাহরণ

{
  "version": 2,
  "status": "fail",
  "message": null,
  "tests": [
    {
      "name": "Test that the thing works",
      "status": "fail",
      "message": "Expected 42 but got 123123",
      "output": "Debugging information output by the user",
      "test_code": "assert_equal 42, answerToTheUltimateQuestion()"
    }
  ]
}

v3 উদাহরণ

{
  "version": 3,
  "status": "fail",
  "message": null,
  "tests": [
    {
      "name": "Test that the thing works",
      "status": "fail",
      "message": "Expected 42 but got 123123",
      "output": "Debugging information output by the user",
      "test_code": "assert_equal 42, answerToTheUltimateQuestion()",
      "task_id": 1
    }
  ]
}

UI/UX সংক্রান্ত বিষয়

টেস্ট ব্যর্থ হলে

শিক্ষার্থীর সলিউশন কোনো টেস্টে ব্যর্থ হলে, এমন কিছু দেখানো উচিত:

Test Code:
  <test_code>

Test Result:
  <message>

টেস্ট সফল হলে

সলিউশন কোনো টেস্ট পাস করলে, এমন কিছু দেখানো উচিত:

Test Code:
  <test_code>

আপনার ভাষার টেস্ট স্যুটে মেটাডেটা কীভাবে যোগ করবেন

সব পথই রোমে গিয়ে মেশে, এবং এখানে পৌঁছানোর জন্য কোনো নির্দিষ্ট প্যাটার্ন বাধ্যতামূলক নয়। এখন পর্যন্ত বেশ কিছু পদ্ধতি অবলম্বন করা হয়েছে:

  • ম্যানুয়ালি কম্পাইল করা সহায়ক JSON ফাইল, যা টেস্ট রানটাইমে টেস্ট ফলাফলের সাথে একত্র করা হয়।
  • টেস্ট স্যুটের স্বয়ংক্রিয় স্ট্যাটিক বিশ্লেষণ, যা টেস্ট রানটাইমে টেস্ট ফলাফলের সাথে একত্র করা হয়।
    • এটি AST বিশ্লেষণ বা টেক্সট-পার্সিংয়ের মাধ্যমে করা যেতে পারে