Unity Game Engine: اختبار (TDD) في Unity 3D
التطوير القائم على الاختبار (TDD) هو ممارسة كتابة الاختبارات الآلية
لجزء من التعليمات البرمجية قبل كتابة الكود نفسه.
هذا يعني في الأساس أننا نقوم بإنشاء وإعادة بناء (تغيير الهيكل دون تغيير السلوك)
رمز مشروعنا على أساس الاختبارات. تتبع عملية كتابة الكود ،
واختبار الكود وإعادة بناءه ، بعضها البعض في حلقة ، حتى يتم الوصول إلى حالة مرضية.
يتم اتباع التسلسل التالي للخطوات بشكل عام :
- أضف اختبارًا (سيفشل في البداية)
- قم بتشغيل جميع الاختبارات ومعرفة ما إذا كان الاختبار الجديد قد فشل
- اكتب بعض التعليمات البرمجية
- تشغيل الاختبارات
- كود إعادة البناء
- التكرار .
يؤدي اتباع سير العمل هذا إلى تسريع عملية إعادة بناء التعليمات البرمجية
وإجراء التغييرات ، لأنه يمكنك أن ترى على الفور ما تعطل ولماذا.
قد تتساءل لماذا نكتب الاختبار قبل كتابة الكود نفسه.
هذا لأن كتابة الاختبارات بعد كتابة الكود يمكن أن يؤدي
غالبًا إلى قيام المطورين بكتابة الاختبارات لاجتيازها.
عندما تكتب اختبارًا فاشلاً أولاً ، فأنت تتأكد من فشله لسبب وجيه
(مثل عدم تنفيذ الوظيفة المطلوبة بشكل صحيح) ، وكذلك استبعاد الإيجابيات الخاطئة.
اهم مميزات حلقة TDD
الأحمر - الأخضر - Refactor
أهم شيء يجب أخذه في الاعتبار هو حلقة إعادة البناء باللون الأحمر والأخضر.
إنه قلب وروح عملية TDD. هنا كل خطوة لها معنى:
- الاحمر :
يشير إلى كتابة حالة اختبار ستفشل بالتأكيد.
- أخضر:
يشير إلى تغيير / كتابة الكود الذي سيجعل الاختبار الذي تم إنشاؤه في
المرحلة "الحمراء" يمر بطريقة تجعل جميع الاختبارات التي تم اجتيازها سابقًا لا تزال تمر.
هذا يعني أنه يجب على المطور ألا يكسر عمل المشروع لاجتياز اختبار واحد فقط.
- المراجع Refactor :
يشير إلى القضاء على التكرار ، وزيادة قابلية القراءة ،
وما إلى ذلك من الشفرة المكتوبة.
تتكرر هذه الخطوات مرارًا وتكرارًا حتى تجتاز جميع الاختبارات أو
تكون مواجهة اختبار فاشل أمرًا مستحيلًا / غير محتمل.
وحدة التجارب في TDD
اختبار Unity هو مستوى اختبار البرنامج حيث
يتم اختبار الوحدات / المكونات الفردية للبرنامج.
والغرض من ذلك هو التحقق من أن كل وحدة من البرنامج تعمل حسب التصميم.
الوحدة هي أصغر جزء قابل للاختبار في أي برنامج.
وعادة ما يكون له مدخل واحد أو عدة مدخلات وعادة ما يكون ناتجًا منفردًا.
حان الوقت للحصول على مثال !
الآن ما نؤمن به هو أن العمل يتحدث بصوت أعلى من الكلمات.
ومن ثم ، فإن أداء المهمة هو أفضل شكل من أشكال التعلم.
ومن ثم فإن ما سنهدف إليه هو إعداد سيناريو اختبار وحدة أساسية حيث
يمكننا اختبار ما إذا كانت وظيفة فئة معينة تؤدي وظيفتها كما هو متوقع.
سننشئ قيمة تربيعية حلالا والتي عند إعطاء المدخلات كـ "x" ، نتلقى قيمة f (x).
على سبيل المثال.
دع f (x) = x2 -4x + 4 الآن للحصول على قيمة x = 2 ، نحصل على f (2) = 0.
نهدف إلى إنشاء هذا باستخدام عملية TDD.
الآن في Unity ، بعد فتح مشروع جديد ، انقر فوق Window> Test Runner في شريط القائمة.
تظهر الآن نافذة مثل هذه.
هذه هي وحدة اختبار الوحدة الداخلية لـ Unity. سوف نستفيد من خدماتها لـ TDD.
قم بإرفاق علامة التبويب هذه عن طريق سحبها بجوار المراقب (قم بذلك بنفسك).
الآن علينا أن نعرف أن نصوص الاختبار ليست مثل نصوصنا العادية.
لجعل محرر Unity يتعامل مع برنامج نصي معين باعتباره نص اختبار ،
فإن الخطوة الأولى هي حفظ النص في مجلد معين يسمى "محرر" (بدون علامات الاقتباس).
وبالتالي ، قم بإنشاء مجلد "Editor" في الأصول وإنشاء
نص برمجي يسمى "FunctionTester" بداخله .
الآن بعد اكتمال الإعداد ، سنبدأ بعملية التطوير.
هنا سنستخدم حلقة Red-Green-Refactor .
وبالتالي سنكتب أولاً اختبارًا يفشل (من الضروري أن نجعل الاختبار يفشل).
بعد ذلك سنحاول تصحيح الكود بحيث يعطي الاختبار نتيجة إيجابية.
ثم أخيرًا سنحاول جعل الكود الخاص بنا نظيفًا ومقروءًا قدر الإمكان.
افتح البرنامج النصي FunctionTester واكتب التعليمات البرمجية التالية فيه.
using System;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
[TestFixture]
public class FunctionTester
{
[Test]
public void T00_PassingTest ()
{
Assert.AreEqual (1, 0);
}
}
الآن في علامة التبويب عداء الاختبار ، انقر فوق تشغيل الكل .
هذا هو الانتهاء من أول حالة حمراء لنا.
تم ذكر المكان الذي فشل فيه الاختبار أسفل علامة التبويب.
الآن بالنسبة إلى الحالة الخضراء ، نحتاج إلى تصحيح الكود بحيث تكون الحالة صحيحة.
للقيام بذلك ، قم بتغيير السطر 11 من الكود إلى
Assert.AreEqual (1, 1);
الآن عند النقر فوق تشغيل جميع ، تعود جميع الاختبارات إلى الحقيقة.
لا نحتاج إلى حالة إعادة بناء في هذا التكرار لأن الكود في أبسط أشكاله.
يمكن تخطي حالة إعادة البناء فقط إذا شعر المطور أن الشفرة مرضية.
الآن يجب أن تفكر في ما يفعله هذا الرمز. س
هنا في السطر 5 ، نصف الفصل بأنه [TestFixture]. هذا يخبر Unity
أن هذا الفصل هو فئة Tester الخاصة بنا وسيتم استخدامه لاختبار الوحدة.
سنقوم الآن بإجراء كل اختبار من اختباراتنا كوظائف.
قبل تعريف الوظيفة نذكر أنها [اختبار].
يتيح ذلك لعامل الاختبار الوصول إليه وإظهار النتيجة لنا.
الاختبار الأول ، كما ترى ، تافه جدًا ، لكن من الممارسات الجيدة كتابة الاختبار الأول
على أنه تافه لأنه يتأكد من أن نظام الاختبار يعمل بشكل صحيح.
[Test]
public void T00_PassingTest ()
{
Assert.AreEqual (1, 0);
}
Assert.AreEqual هي إحدى وظائف فئة Assert من مكتبة Nunit.
إنه يتحقق مما إذا كان الكائنان اللذان تم تمريرهما إليه متساويين أم لا.
يتم طرح AssertionException إذا كانت الكائنات غير متساوية.
هذا ينهي التكرار الأول لدينا.
بعد ذلك سنختبر أنه عندما x = 2 ، يجب أن نحصل على القيمة 0 من المعادلة التربيعية.
الآن في التكرار الثاني سنقوم بتعديل الكود كما يلي :
using System;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
[TestFixture]
public class FunctionTester
{
public Function function = new Function();
[Test]
public void T00_PassingTest ()
{
Assert.AreEqual (1, 1);
}
[Test]
public void T01_X2Y0()
{
Assert.AreEqual(function.Value(2f) ,0f);
}
}
هنا بدأنا حلقة RGR الثانية (الأحمر والأخضر والمعكس).
عند إجراء هذا الاختبار ، سوف نفشل في الاختبار T01.
الآن سترى أن هذا لا يترجم. هذا لأنه ليس لدينا فئة دالة.
هذا هو المكان الذي يبدأ اختبارنا الحقيقي.
داخله اكتب الكود:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Function
{
public float Value (float x)
{
return 8f;
}
}
الآن عند إجراء الاختبار ، حصلنا على فشل.
بالانتقال نحو الحالة الخضراء ، سنغير السطر 9 من نص الوظيفة إلى
return 0f;
الآن عند إجراء الاختبار مرة أخرى ، سنحصل على نتيجة إيجابية .
يجب أن تفكر الآن لماذا لم نحسب أي شيء في الوظيفة.
عليك أن تدرك أن الهدف الوحيد الذي لدينا في TDD هو أن
نجتاز جميع الاختبارات وأن هذه الطريقة تجتاز الاختبارات بشكل جيد.
في التكرار التالي ، سنختبر عندما x = 0 ، f (0) = 4. تنفيذ الاختبار في
FunctionTester لتكرار الاختبار هذا (التحدي!).
حاول ألا تنسخ الكود وتكتبه بنفسك. تذكر ، الأخطاء هي أفضل المعلمين.
اعرض الكود أدناه وقارن بين الأخطاء:
using System;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
[TestFixture]
public class FunctionTester
{
public Function function = new Function();
[Test]
public void T00_PassingTest ()
{
Assert.AreEqual (1, 1);
}
[Test]
public void T01_X2Y0()
{
Assert.AreEqual(function.Value(2f) ,0f);
}
[Test]
public void T02_X0Y4()
{
Assert.AreEqual (function.Value (0f), 4f);
}
}
سيفشل هذا الاختبار لأن دالة القيمة الخاصة بنا ترجع 0f بغض النظر عن المدخلات.
الآن من أجل الولاية الخضراء. ما نريده هو دالة القيمة لحساب
قيمة المعادلة التربيعية لـ x حيث f (x) = x2-4x + 4 .
وبالتالي سنقوم بتغيير دالة القيمة الخاصة بنا إلى:
public float Value (float x)
{
return (Mathf.Pow (x,2) - (4f*x) + 4f);
}
الآن نصل إلى حالة إعادة البناء.
بالنظر إلى وظيفتنا ، يمكننا أن نرى أنها صغيرة جدًا بحيث لا تؤثر
إعادة البناء على الكود الخاص بنا كثيرًا.
تصبح إعادة الهيكلة مهمة في النصوص الكبيرة.
الآن كمهمة ، حاول كتابة أكبر عدد ممكن من الاختبارات في فئة FunctionTester
واتبع حلقة RGR لإنجاح الاختبارات.
كلما زاد عدد الاختبارات ، زادت دقة Unity .
ماذا تفعل إذا فشل اختبار سابق أثناء Green State ؟
ضع في اعتبارك إمكانية إجراء تغييرات على البرنامج النصي لإجراء اختبار معين.
يؤدي هذا التغيير إلى فشل أحد الاختبارات السابقة التي كانت تمر من قبل .
إذا حدث هذا ، فبدلاً من الانتقال إلى النص التالي ،
سندخل مرة أخرى الحالة الحمراء لحالة الاختبار تلك.
لن ننتقل إلى حالات الاختبار الجديدة إلا إذا نجحت جميع حالات الاختبار السابقة .
الخلاصة :
كان هذا مثالاً على إنشاء مشاريع أساسية وبسيطة للغاية بواسطة TDD.
قد يبدو هذا وكأنه ألم في المثال ، ولكن عندما يتم
توسيع نطاقه (للمشاريع الأكبر) ، فإن TDD هو نعمة.
يساعد على تحديد الأخطاء وتصحيحها بطريقة سريعة وفعالة.
لذا حاول استخدامه في المشاريع التي يمكن أن تحدث فيها الكثير من السيناريوهات.
يساعد هذا أيضًا في تتبع جميع السيناريوهات التي تم اختبارها.