آزمایش کردن در مسیر Arturo

بیاموزید چطور تمرین‌های Arturo خود را در Exercism آزمایش کنید


مسیر Arturo برای همه‌ی تست‌های تمرین‌ها از بسته‌ی تست واحد Unitt 3.0.0 استفاده می‌کند. این بسته یک framework برای تست فراهم می‌کند که هم از نحوه‌ی نگارش مدرن الهام‌گرفته از RSpec پشتیبانی می‌کند و هم از نحوه‌ی نگارش قدیمی الهام‌گرفته از XUnit. اجرای arturo tester.art یا exercism test از داخل پوشه‌ی تمرین محلی‌تان، در اولین اجرا بسته را از اینترنت نصب می‌کند. در غیر این صورت، می‌توانید Unitt را با اجرای arturo --package install unitt 3.0.0 نصب کنید. فقط اولین تست اجرا می‌شود و نتیجه‌ی آن به شما گزارش می‌شود. وقتی آن تست قبول شد، حالت skip را از تست بعدی بردارید و دوباره تست‌ها را اجرا کنید تا هر تست قبول شود. در هر دو حالت RSpec و XUnit، این کار به همین سادگی است که .skip را به‌ترتیب از it.skip یا test.skip حذف کنید. وقتی همه‌ی تست‌ها قبول شدند، راه‌حل خود را ارسال کنید، اما توجه داشته باشید که اجراکننده‌ی تست همه‌ی تست‌ها را اجرا می‌کند، حتی تست‌هایی که skip شده‌اند.

شروع به کار

پوشه‌ی تمرینی که دانلود کرده‌اید چند فایل دارد، اما این سه فایل ضروری‌اند.

leap/
├── src/leap.art         # Your solution file
├── tests/test-leap.art  # Test cases for the exercise
└── tester.art           # Test runner entry point

اجرای arturo tester.art ابتدا Unitt را راه‌اندازی می‌کند و سپس تست‌های داخل tests/test-leap.art را اجرا می‌کند. تست‌ها فایل src/leap.art را که شامل راه‌حل شماست import می‌کنند و سپس مجموعه‌ای از ادعاها را درباره‌ی آنچه راه‌حل شما باید برای ورودی‌های مشخص برگرداند انجام می‌دهند.

فایل راه‌حل

isLeap?: function [year][
    panic "please implement the isLeap? function"
]

وقتی یک تمرین را شروع می‌کنید، فایل راه‌حل شما با یک قالب همراه است که ساختار پایه‌ای آنچه انتظار می‌رود را در بر دارد. در این نمونه از Leap، فایل شامل تعریفی حداقلی از تابع موردانتظار isLeap? است و به‌طور خاص یک panic که اجرای تست را متوقف می‌کند. خط panic را حذف کنید و سپس نوشتن پیاده‌سازی خود برای isLeap? را آغاز کنید.

ساختار تست RSpec

import.version:3.0.0 {unitt}!
import {src/leap}!

describe "Leap" [
    it "a year not divisible by 4 is a common year" [
        expects.be:'false? @[isLeap? 2015]
    ]

    it.skip "a year divisible by 4 and not divisible by 100 is a leap year" [
        expects.be:'true? @[isLeap? 1996]
    ]
]
  • describe بلوکی از test caseها را تعریف می‌کند که چیزی مشترک را اعتبارسنجی می‌کنند. این بلوک‌ها می‌توانند تودرتو باشند.
  • it و it.skip هر دو یک test case واحد را تعریف می‌کنند که به‌ترتیب اجرا یا skip می‌شود.
  • expects ادعایی را معرفی می‌کند که قلب یک test case است. expects.be یک تابع شرطی می‌گیرد که برای ساختن آن ادعا به کار می‌رود.

در expects.be:'false? @[isLeap? 2015]، مجموعه‌ی تست ادعا می‌کند که تابع isLeap? باید برای سال ۲۰۱۵ مقدار false را برگرداند. روش دیگری برای نوشتن آن expects.be:'equal? @[false isLeapYear? 2015] است که در آن ادعا می‌کنیم مقدار برگردانده‌شده‌ی isLeapYear? 2015 با false برابر است. این شکل طولانی‌تر که دو مقدار را مقایسه می‌کند، رایج‌ترین نوع ادعا در مسیر Arturo است. مقدار موردانتظار همیشه پیش از مقدار نتیجه در بلوک می‌آید.

ساختار تست XUnit

suite "Leap" [
    test "a year not divisible by 4 is a common year" [
        result: isLeap? 2015
        assert -> false = result
    ]

    test.skip "a year divisible by 4 and not divisible by 100 is a leap year" [
        result: isLeap? 1996
        assert -> true = result
    ]
]

API شبیه XUnit که در v1 کتابخانه‌ی Unitt معرفی شد، برای سازگاری با نسخه‌های پیشین پشتیبانی می‌شود و به‌جز ادعاهای کم‌انعطاف‌ترش، تقریباً با API مدرن شبیه RSpec برابر است.

  • suite بلوکی از test caseها را تعریف می‌کند که چیزی مشترک را اعتبارسنجی می‌کنند. این بلوک‌ها می‌توانند تودرتو باشند.
  • test و test.skip هر دو یک test case واحد را تعریف می‌کنند که به‌ترتیب اجرا یا skip می‌شود.
  • assert ادعایی را معرفی می‌کند که قلب یک test case است. عبارتی که در سمت راست -> می‌آید باید «درست» باشد.

در تست‌های XUnit، معمولاً پیش از خط assert، متغیرهایی ساخته می‌شوند که نتیجه و به‌صورت اختیاری مقدار موردانتظار را نگه می‌دارند.

خروجی تست

چه از API شبیه RSpec استفاده کنید و چه از API شبیه XUnit، خروجی تست تقریباً مشابه خواهد بود. تنها تفاوت در چیزی است که زیر نام هر تست چاپ می‌شود. XUnit ادعا را با استفاده از مقادیر ارزیابی‌شده گزارش می‌کند، بنابراین false = false را می‌بینید. اما RSpec آن را به‌صورت false? false گزارش می‌کند، چون از تابع false? همراه با expects استفاده کردیم.

از ابتدا شروع کنیم: اگر panic فایل اولیه حذف نشده باشد، Arturo یک خطا گزارش می‌کند و هیچ تستی را ارزیابی نمی‌کند.

Uncaught error in tests/test-leap.art:
#[
        output: {
                
                ══╡ Program Error ╞═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════ <script> ══
                
                  Please implement the isLeap? function
                
                
        }
        code: 1
]

وقتی panic جایگزین شد، Arturo وضعیت هر ادعای انجام‌شده در یک تست را گزارش می‌کند. حالا اولین تست قبول می‌شود، اما تست دوم skip شده است.

======== .unitt/tests/test-leap.art ========

Describe: Leap

    ✅ - assert that a year not divisible by 4 is a common year
         ✅: false? false

    ⏩ - assert that a year divisible by 4 and not divisible by 100 is a leap year
         skipped!


========== Summary ==========

⏏️   TOTAL: 2 assertions
✅  PASSED: 1 assertion
⏩ SKIPPED: 1 assertion
❌  FAILED: 0 assertion

========== ======= ==========

پس از آنکه skip از تست دوم به‌صورت دستی برداشته شد، هر دو تست اجرا می‌شوند. اما پیاده‌سازی فعلی isLeap? تنها false را برمی‌گرداند، بنابراین تست دوم در ادعایش شکست می‌خورد.

======== .unitt/tests/test-leap.art ========

Describe: Leap

    ✅ - assert that a year not divisible by 4 is a common year
         ✅: false? false

    ❌ - assert that a year divisible by 4 and not divisible by 100 is a leap year
         ❌: true? false


========== Summary ==========

⏏️   TOTAL: 2 assertions
✅  PASSED: 1 assertion
⏩ SKIPPED: 0 assertion
❌  FAILED: 1 assertion

========== ======= ==========

همان‌طور که تست‌های بیشتری را از حالت skip درمی‌آورید، این روند ادامه می‌یابد. وقتی همه‌ی تست‌ها قبول شدند، تمرین را تمام کرده‌اید و می‌توانید راه‌حل را ارسال کنید. توجه داشته باشید که اجراکننده‌ی تست، صرف‌نظر از اینکه تست‌ها به‌صورت محلی skip شده باشند یا نه، همه‌ی آن‌ها را اجرا می‌کند.