الأدوات الصناعية: JUnit و PHPUnit و NUnit
إطارٌ لكل لغة، ومبدأٌ واحد يجمعها: كيف تقرأ أيّ اختبارٍ مهما كانت لغته؟ ⏱ نحو 40 دقيقة.
- تعرف أطر اختبار الوحدة لكل لغة.
- تقرأ اختبارًا بأيّ لغة من عائلة
xUnit. - تطبّق نمط
AAA. - تدرك أن المبدأ واحد عبر اللغات.
١الفكرة واحدة، اللغة تختلف
تعلّمت الاختبار ببايثون. لكنّ تطبيقات الويب تُكتَب بلغاتٍ شتّى، ولكلٍّ إطار اختبار وحدةٍ من عائلة xUnit نفسها — المصطلحات نفسها (TestCase، assert، setUp)، والصياغة تختلف:
| اللغة | إطار اختبار الوحدة | يُستخدم في |
|---|---|---|
| Java | JUnit | الواجهات الخلفية بـ Spring |
| PHP | PHPUnit | تطبيقات Laravel و WordPress |
| C# / .NET | NUnit / xUnit | خوادم ASP.NET |
| JavaScript | Jest | الواجهات والـ Node |
| Python | unittest / PyTest | Django و Flask |
مَن فهم المبدأ ببايثون يقرأ أيّها بسهولة: assertEqual هي assertEquals هي expect(...).toBe. تتعلّم الفكرة مرّة، وتطبّقها بأيّ لغة.
٢الاختبار نفسه بثلاث لغات
اختبار دالة جمعٍ بسيطة. لاحظ تطابق البنية: ترتيب-تنفيذ-تأكيد (Arrange-Act-Assert):
// JUnit — Javapublic class CalcTest { @Test public void testAdd() { assertEquals(5, Calc.add(2, 3)); } }
// PHPUnit — PHPclass CalcTest extends TestCase { public function testAdd() { $this->assertEquals(5, Calc::add(2, 3)); } }
import unittestdef add(a, b): return a + b class CalcTest(unittest.TestCase): def test_add(self): self.assertEqual(add(2, 3), 5) import sysunittest.main(argv=[""], exit=False, testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
ثلاث لغات، بنيةٌ واحدة. الوحيد الذي يعمل هنا هو بايثون (في متصفحك)، لكنك الآن تقرأ الثلاثة.
٣نمط AAA: ترتيب، تنفيذ، تأكيد
كل اختبارٍ جيّد يتبع ثلاث خطوات واضحة، مهما كانت اللغة:
| الخطوة | المعنى | مثال |
|---|---|---|
| Arrange ترتيب | جهّز المدخلات والبيئة | cart = Cart() |
| Act تنفيذ | استدعِ ما تختبره | cart.add("x") |
| Assert تأكيد | تحقّق من النتيجة | assertEqual(cart.total(), 1) |
توقّع وتحقّق
إطار اختبار الوحدة في PHP:
إطار اختبار الوحدة في Java:
عائلة أطر اختبار الوحدة تسمّى:
نمط AAA يعني:
الخلاصة
- لكل لغةٍ إطار اختبار وحدةٍ من عائلة
xUnit: JUnitوPHPUnitوNUnitوJestوunittest. - المصطلحات والبنية متطابقة؛ من فهم المبدأ ببايثون يقرأ أيّها.
- نمط
AAA: رتّب المدخلات، نفّذ ما تختبره، أكّد النتيجة. - الفصل الواضح للخطوات يجعل الاختبار مقروءًا وقابلًا للصيانة.
تحدٍّ برمجي: طبّق AAA
متوسطاكتب اختبار unittest لدالة join_name متّبعًا نمط AAA بوضوح (ترتيب ثم تنفيذ ثم تأكيد)، ثم شغّله. اختبر join_name("سعود","الحربي")=="سعود الحربي".
- رتّب المدخلات، ثم استدعِ الدالة، ثم أكّد النتيجة.
- شغّل بالمُشغّل المعطى.
ابدأ من هذا الكود، واضغط ▶ شغّل هنا لتكتب حلّك وتجرّبه مباشرة:
import unittestdef join_name(first, last): return first + " " + last# اكتب اختبارًا بنمط AAA ثم شغّلهimport sys
💡 تلميح 1
first, last = ... ثم نفّذ: result = join_name(...).💡 تلميح 2
self.assertEqual(result, "سعود الحربي").حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
import unittestdef join_name(first, last): return first + " " + lastclass TestJoin(unittest.TestCase): def test_full_name(self): first, last = "سعود", "الحربي" # Arrange result = join_name(first, last) # Act self.assertEqual(result, "سعود الحربي") # Assertimport sysrunner = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)unittest.main(argv=[""], exit=False, testRunner=runner)