نشرح في هذه المقالة كيفية استخدام أداة الذكاء الاصطناعي BlackBoxAI في اختبار البرامج، وهي المهمة التي تضمن استقرار عمل الأنظمة التي نطورها، خاصة في التطبيقات الحيوية التي تكون تكلفة الخطأ فيها كبيرة مثل تطبيقات التكنولوجيا المالية أو القيادة الذاتية للمركبات، إضافة إلى التصنيفات الأخرى من التطبيقات التي نرغب باختبارها.
تعريف اختبار البرامج
اختبار البرامج Software testing هو تقييم التطبيقات البرمجية التي نطورها من حيث الأداء والوظائف التي تؤديها لنتأكد من استيفاء هذه البرامج للمتطلبات المستهدفة منها وأنها تخلو من الأخطاء والعيوب، وتُختبر البرامج إما آليًا أو يدويًا.
ويقسَّم اختبار البرامج من منظور آخر إلى اختبار وظيفي Functional testing واختبار غير وظيفي Non-Functional testing، حيث تقيس الاختبارات الوظيفية أداء الوظائف الأساسية المطلوبة من النظام مثل التحقق من معالجة البيانات المدخلة بشكل صحيح بينما يقيس الاختبار غير الوظيفي مزايا وصفية وليست وظيفية للنظام، مثل اختبار الأداء Performance testing أو اختبار قابلية الاستخدام Usability أو اختبار سهولة الوصول Accessibility.
متطلبات العمل
-
تنزيل محرر أكواد مناسب مثل VS Code
-
تثبيت مكتبات بايثون التالية
fastapiوuvicornوlocustباستخدام الطرفية:
pip install fastapi uvicorn locust
مستويات اختبار البرامج Software testing levels
ذكرنا أول المقال أننا نختبر البرامج لنضمن عملها وأداءها لوظائفها، وأدنى هذه المستويات هو اختبار الوحدة unit test، ثم اختبار التكامل Integration test الذي يقيس توافقية الوحدات البرمجية المختلفة مع بعضها البعض عند دمجها، يلي هذا اختبار النظام بشكل شامل System testing، ثم اختبارات القبول في المستوى النهائي التي ينفذها المستخدم حيث يختبر الوظائف المطلوبة بشكل كامل ليقيس جاهزيتها للتسليم.
اختبار الوحدات البرمجية unit test
يمثل اختبار الوحدات البرمجية أدنى مستوى من اختبار البرامج حيث يفحص أصغر الأجزاء القابلة للتنفيذ في الشيفرة مثل الدوال البرمجية Functions أو الأصناف classes أو التوابع methods، ويتم هذا الاختبار في بيئة معزولة عن باقي مكونات النظام أو أي أنظمة خارجية مثل قواعد البيانات أو واجهات التطبيقات البرمجية APIs لأن المشكلات التي قد تحدث في هذا المستوى ستؤثر على غيره، فإذا كنا نصمم برنامج آلة حاسبة سنحتاج للتأكد من عمل كل وظيفة بشكل مستقل، فنختبر دالتي الجمع والطرح وغيرها من الدوال الوظيفية اختبارات مستقلة لنضمن سلاسة وسلامة الانتقال للمستوي التالي الذي يدمج عدة عمليات رياضية معًا.
اختبار تحويل الأموال في نظام بنكي
لنفرض أن لدينا نظام بنكي فيه صنف class اسمه BankAccount مسؤول عن إنشاء كائنات حسابات بنكية، ويحتوي تابع method باسم transfer مسؤول عن تحويل الأموال من حساب لآخر.
class BankAccount: def __init__(self, balance: float): self.balance = balance # دالة لإيداع الأموال def transfer(self, target_account, amount: float): # التحقق من أن الحساب ليس مديونًا أو مفلسًا if amount <= 0: raise ValueError("ينبغي أن يكون المبلغ أكبر من الصفر.") # التحقق من أن الرصيد كافي if self.balance < amount: raise ValueError("الرصيد غير كافي") # خصم المبلغ من الحساب المرسل self.balance -= amount # إيداع المبلغ في الحساب المستهدف target_account.balance += amount
نختبر الآن دالة تحويل الأموال في معزل عن باقي النظام باستخدام أداة BlackBox AI، من خلال توليد حالات اختبار مناسبة باستخدام مكتبة pytest لأنها من أبسط المكتبات المتاحة في لغة بايثون لتنفيذ اختبار على مستوى الوحدة، وبما أننا ثبتنا إضافة BlackBox AI في محرر Vscode فستكون موجودة في القائمة الجانبية في يسار المحرر، ونخبرها أن تنشئ ملف اختبار لوظيفة تحويل الأموال بين الحسابات البنكية كما يلي:
> create a test file in python using pytest library to test the method of transfer in BankAccount class @/BankAccount.py
نلاحظ أن BlackBoxAI وضعت خطة لتنفيذ الطلب ثم أنشأت ملف test_BanckAccount.py وتطلب مصادقتنا على التغييرات المقترحة والتي يمكن تصفحها قبل الموافقة عليها أو رفضها.
بالنظر في ملف test_BanckAccount.py سنجد أن الأداة قد ولدت الشيفرة التالية:
import pytest from BankAccount import BankAccount def test_transfer_successful_transfer(): account1 = BankAccount(100) account2 = BankAccount(50) account1.transfer(account2, 50) assert account1.balance == 50 assert account2.balance == 100 def test_transfer_with_zero_amount(): account1 = BankAccount(100) account2 = BankAccount(50) with pytest.raises(ValueError, match="ينبغي أن يكون المبلغ أكبر من الصفر."): account1.transfer(account2, 0) def test_transfer_with_negative_amount(): account1 = BankAccount(100) account2 = BankAccount(50) with pytest.raises(ValueError, match="ينبغي أن يكون المبلغ أكبر من الصفر."): account1.transfer(account2, -10) def test_transfer_with_insufficient_balance(): account1 = BankAccount(50) account2 = BankAccount(100) with pytest.raises(ValueError, match="الرصيد غير كافي"): account1.transfer(account2, 100)
نشغل هذا الملف الاختباري بالأمر التالي في سطر الأوامر Terminal
pytest test_BankAccount.py
ونحصل على الخرج التالي:
===========================
platform win32 -- Python 3.9.12, pytest-7.1.1, pluggy-1.0.0
rootdir: F:\AI_tools\Article_4
plugins: anyio-3.5.0
collected 4 items
test_BankAccount.py ....
============================= 4 passed in 0.21s =====================[100%]
وهكذا نكون قد تجاوزنا جميع الاختبارات بنجاح، لكن هذا لا يعني أن الشيفرة ليست بها مشاكل، فيجب أن نتأكد من اختبار الحالات المتطرفة من الاستخدام edge cases التي قد تتسبب في انهيارها أو حدوث مشاكل فيها، سواء اعتمدنا على أدوات الذكاء الصناعي أو أجرينا الاختبارات يدويًا.
وينبغي أن نسعى لاختبار أكبر عدد ممكن من السيناريوهات لاكتشاف المشاكل مبكرًا -رغم صعوبة التنبؤ بجميع الحالات المسببة للمشاكل- ذلك أن تكلفة معالجة الأخطاء أثناء مرحلة التطوير أقل من تكلفة إصلاحها بعد إطلاق البرنامج نفسه وتفاعل المستخدمين معه.
لذا سنطلب من BlackBoxAI أن يغطي نطاقًا أوسع من حالات الاستخدام مع التركيز على الحالات المتطرفة لضمان استقرار النظام، كما يمكن مناقشته كذلك في حالات اختبار أخرى من من فهمنا لاحتياج النشاط التجاري -البنك في حالتنا- ومراجعة النتائج التي تعود بها علينا للتأكد من مناسبتها لحالة الاستخدام لدينا فلن تعطل وظيفة عاملة بالفعل، فالأداة عرضة للخطأ مهما بلغت من براعة. على سبيل المثال، نريد التأكد من قدرة النظام على التعامل مع الأخطاء غير المتوقعة، مثل فشل عملية تحويل الأموال لأي سبب:
> I want to test edge cases to ensure all transactions are atomic, especially when a transaction fails. Specifically, I need to verify that the balance remains unchanged if the sending or receiving process fails, using pytest.
اقترحت الأداة بعد هذا الموجه إجراء محاكاة عملية لوقوع خطأ بعد خصم مبلغ من حساب المرسل، ويفشل النظام إذا تم الخصم حقًا من حساب المرسل دون أن يستلم الطرف الثاني أي أموال.
import pytest from BankAccount import BankAccount def test_transfer_successful_transfer(): account1 = BankAccount(100) account2 = BankAccount(50) account1.transfer(account2, 50) assert account1.balance == 50 assert account2.balance == 100 def test_transfer_with_zero_amount(): account1 = BankAccount(100) account2 = BankAccount(50) with pytest.raises(ValueError, match="ينبغي أن يكون المبلغ أكبر من الصفر"): account1.transfer(account2, 0) def test_transfer_with_negative_amount(): account1 = BankAccount(100) account2 = BankAccount(50) with pytest.raises(ValueError, match="ينبغي أن يكون المبلغ أكبر من الصفر"): account1.transfer(account2, -10) def test_transfer_with_insufficient_balance(): account1 = BankAccount(50) account2 = BankAccount(100) with pytest.raises(ValueError, match="الرصيد غير كافي"): account1.transfer(account2, 100) def test_transfer_mid_transaction_failure(): """ محاكاة فشل العملية بعد خصم المبلغ وقبل إيداعه. السلوك المتوقع: يجب ألا يفقد المرسل المال إذا فشلت العملية. """ account1 = BankAccount(100) account2 = BankAccount(50) # إنشاء حساب يحتوي على خطأ محتمل عند محاولة إعادة تعيين الرصيد class ProblematicAccount: def __init__(self, balance): self.balance = balance # الحصول على الرصيد بشكل آمن # getter @property def balance(self): return self._balance # تعيين الرصيد بشكل آمن # setter @balance.setter def balance(self, value): if hasattr(self, '_balance'): # إن كانت القيمة معرفة مسبقًا raise RuntimeError("Unexpected failure before deposit!") self._balance = value problem_account = ProblematicAccount(50) # اختبار نقل الأموال with pytest.raises(RuntimeError, match="Unexpected failure before deposit!"): account1.transfer(problem_account, 30) # التحقق من عدم فقدان المرسل للمال بشكل غير متوقع assert account1.balance == 100, "Sender lost money unexpectedly!" assert problem_account.balance == 50, "Receiver should not gain money!"
ينبغي أن نحصل على الخرج التالي بتشغيل تلك الشيفرة:
=========================== short test summary info ========================
FAILED test_BankAccount.py::test_transfer_mid_transaction_failure - AssertionError: Sender lost money unexpectedly!
================ 1 failed, 4 passed in 0.14s =================================
ندرك بهذا أن الدالة transfer تحتاج للتعديل لتتمكن من التعامل مع حالات الفشل غير المتوقعة، خاصة تحقيق مبدأ الذرية Atomic الذي ينص على أن العملية ينبغي أن تنجح بالكامل أو تفشل بالكامل، ونحقق ذلك بتطبيق آلية للتراجع في حالة حدوث خطأ غير متوقع، انظر الموجه التالي.
> Given that failure on the atomicity test case (test_transfer_mid_transaction_failure) ,fix the BankAccount.py transfer method.
ينبغي أن نحصل على الشيفرة المعدلة لملف BankAccount.py
class BankAccount: def __init__(self, balance: float): self.balance = balance def transfer(self, target_account, amount: float): # التحقق من أن الحساب ليس مديونًا أو مفلسًا if amount <= 0: raise ValueError("ينبغي أن يكون المبلغ أكبر من الصفر.") # التحقق من أن الرصيد كافي if self.balance < amount: raise ValueError("الرصيد غير كافي") # حفظ الرصيد الحالي في حالة حدوث خطأ original_balance = self.balance try: # خصم المبلغ من الحساب المرسل self.balance -= amount # إيداع المبلغ في الحساب المستهدف target_account.balance += amount except Exception as e: # استعادة الرصيد الأصلي في حالة حدوث خطأ self.balance = original_balance # إعادة رفع الاستثناء raise e
نستخدم في الشيفرة المعدلة آلية استرجاع Rollback في حال حدوث خطأ في عملية التحويل لئلا تتغير أرصدة الحسابات، مما يضمن بقائها متزامنة وسليمة. نحصل على الخرج التالي عند تشغيل الاختبار:
================================ test session starts ==============
platform win32 -- Python 3.9.12, pytest-7.1.1, pluggy-1.0.0
rootdir: F:\Article_4
plugins: anyio-3.5.0
collected 5 items
test_BankAccount.py ..... [100%]
====================== 5 passed in 0.03s=========================
اختبار الانحدار
اختبار الانحدار Regression test هو نوع من اختبارات البرامج Software testing يستخدم لضمان أن تحديث الشيفرة لا يضر بأي وظيفة كانت تعمل سابقًا، وينفذ عادة بعد تطوير وظائف جديدة أو إصلاح أحد الأخطاء البرمجية، فإذا أردنا إضافة ميزة جديدة للنظام البنكي مثل فرض رسوم على التحويلات، سنطور هذه الميزة ونختبرها لنتأكد من أنها لم تُحدث انحدارًا في التطبيق الموجود، أي ينبغي أن تظل كل المزايا الأخرى وحالات الاختبار تعمل بكفاءة.
class BankAccount: def __init__(self, balance: float, fee_percentage: float = 0): self.balance = balance self.fee_percentage = fee_percentage def transfer(self, target_account, amount: float): # التحقق من أن الحساب ليس مديونًا أو مفلسًا if amount <= 0: raise ValueError("ينبغي أن يكون المبلغ أكبر من الصفر.") # حساب الرسوم المفروضة fee = self.get_fee_amount(amount) total_amount = amount + fee # التحقق من أن الرصيد كافي # مضيفين الرسوم إلى تكلفة التحويل if self.balance < total_amount: raise ValueError("الرصيد غير كافي") # حفظ الرصيد الحالي في حالة حدوث خطأ original_balance = self.balance try: # خصم المبلغ من الحساب المرسل self.balance -= total_amount # إيداع المبلغ في الحساب المستهدف # لا نودع إلا المبلغ المرسل فقد بدون الرسوم target_account.balance += amount except Exception as e: # استعادة الرصيد الأصلي في حالة حدوث خطأ self.balance = original_balance # إعادة رفع الاستثناء raise e def get_fee_amount(self, transfer_amount: float): """حساب مبلغ الرسوم لتحويل معين""" return transfer_amount * self.fee_percentage / 100
نحتاج لاختبار الميزة الجديدة لنتأكد من عمل الوظائف السابقة أولًا، حيث نختبر الحالة التي تكون الرسوم فيها 0% ثم اختبار التحويل حين تكون الرسوم أكبر من الصفر -2% مثلًا-، ونوجه BlackBoxAI حينئذ لتوليد ملف يختبر عمل الوظائف السابقة بالإضافة لاختبار الحالات الجديدة. لنستخدم الموجه التالي:
> Create a regression test for the newly implemented fee feature on money transfers. Ensure the test verifies that the new functionality works as expected, while also confirming that existing features remain unaffected.
ينبغي أن نحصل على ملف اختبار يكون كما يلي:
import pytest from BankAccount import BankAccount # ---------- اختبارات الانحدار (Regression Tests) ---------- # هذه هي الاختبارات الموجودة مسبقًا للتأكد من أن الوظائف الأساسية ما زالت تعمل def test_transfer_successful_transfer(): account1 = BankAccount(100) account2 = BankAccount(50) account1.transfer(account2, 50) assert account1.balance == 50 assert account2.balance == 100 def test_transfer_with_zero_amount(): account1 = BankAccount(100) account2 = BankAccount(50) with pytest.raises(ValueError, match="ينبغي أن يكون المبلغ أكبر من الصفر."): account1.transfer(account2, 0) def test_transfer_with_negative_amount(): account1 = BankAccount(100) account2 = BankAccount(50) with pytest.raises(ValueError, match="ينبغي أن يكون المبلغ أكبر من الصفر"): account1.transfer(account2, -10) def test_transfer_with_insufficient_balance(): account1 = BankAccount(50) account2 = BankAccount(100) with pytest.raises(ValueError, match="الرصيد غير كافي"): account1.transfer(account2, 100) def test_transfer_mid_transaction_failure(): """ محاكاة فشل العملية بعد خصم المبلغ وقبل إيداعه. السلوك المتوقع: يجب ألا يفقد المرسل المال إذا فشلت العملية. """ account1 = BankAccount(100) # إنشاء حساب يحتوي على خطأ محتمل عند محاولة إعادة تعيين الرصيد class ProblematicAccount: def __init__(self, balance): self.balance = balance # الحصول على الرصيد بشكل آمن @property def balance(self): return self._balance # تعيين الرصيد بشكل آمن @balance.setter def balance(self, value): if hasattr(self, '_balance'): # إن كانت القيمة معرفة مسبقًا raise RuntimeError("Unexpected failure before deposit!") self._balance = value problem_account = ProblematicAccount(50) # اختبار نقل الأموال with pytest.raises(RuntimeError, match="Unexpected failure before deposit!"): account1.transfer(problem_account, 30) # التحقق من عدم فقدان المرسل للمال بشكل غير متوقع assert account1.balance == 100, "Sender lost money unexpectedly!" assert problem_account.balance == 50, "Receiver should not gain money!" # ---------- اختبارات الميزة الجديدة (New Feature Tests) ---------- # اختبارات للتحقق من ميزة رسوم التحويل الجديدة def test_transfer_with_fee(): """اختبار التحويل مع وجود رسوم""" # %إنشاء حساب مع رسوم 2 account1 = BankAccount(100, fee_percentage=2) account2 = BankAccount(50) # تحويل 50 وحدة مع رسوم 1 account1.transfer(account2, 50) # التحقق من الأرصدة assert account1.balance == 49, "Should be 100 - 50 - 1(fee) = 49" assert account2.balance == 100, "Should be 50 + 50 = 100" def test_transfer_with_fee_insufficient_balance(): """اختبار فشل التحويل عند عدم كفاية الرصيد لتغطية المبلغ والرسوم""" # إنشاء حساب مع رسوم %10 account1 = BankAccount(100, fee_percentage=10) account2 = BankAccount(50) # محاولة تحويل مبلغ 95 يتطلب مبلغ 9.5 إضافي للرسوم with pytest.raises(ValueError, match="الرصيد غير كافي"): account1.transfer(account2, 95) # التحقق من عدم تغيير الأرصدة assert account1.balance == 100 assert account2.balance == 50 def test_get_fee_amount(): """اختبار حساب مبلغ الرسوم""" account = BankAccount(1000, fee_percentage=2.5) fee = account.get_fee_amount(200) assert fee == 5, "2.5% of 200 should be 5" def test_zero_fee_percentage(): """اختبار أن الحساب يعمل بشكل طبيعي عندما تكون الرسوم صفرًا""" account1 = BankAccount(100, fee_percentage=0) account2 = BankAccount(50) account1.transfer(account2, 50) assert account1.balance == 50 assert account2.balance == 100
بتشغيل ملف الاختبار نجد أنه تجاوز جميع الاختبارات، مما يعني أن الميزة المضافة لم تتسبب في إفساد الميزات الموجودة مسبقًا بالنظام.
اختبارات الأداء
تعد اختبارات الأداء Performance tests أحد الطرق الكمية لقياس المتطلبات غير الوظيفية non-functional requirements مثل قدرة تحمل التطبيق وسرعته في التحميل أو عدد المستخدمين الذين يستطيع التعامل معهم وغيرها من المعايير التي تساعدنا في تحديد حدود الاستخدام المناسبة للتطبيق وتحديد حاجتنا للموارد الحاسوبية من ذاكرة وصول عشوائي RAM أو CPU أو مساحة تخزين.
أنواع اختبارات الأداء Performance test
-
اختبار الحمل Load test : يقيس أداء النظام تحت الظروف المتوقعة أو الطبيعية وسرعة الرد واستخدام الموارد
-
اختبار الضغط Stress test : يختبر حدود النظام بتعريضه لحمل أكبر من المتوقع أو الطبيعي، لمعرفة مدى استقرار النظام ونقاط الفشل وقدرة النظام على التعافي
-
اختبار الحمل المفاجئ Spike test : يختبر أداء النظام تحت حمل عالي ومفاجئ، ويختبر قدرته على التوسع السريع scale up والتعامل مع الضغط المفاجئ
اختبار الحمل في نظام إدارة مخزون
نفترض أن لدينا نظام إدارة مخزون Inventory بسيط يعمل من خلال واجهة تطبيق برمجية API مبنية بمكتبة FastAPI ويرتبط بقاعدة بيانات بسيطة من نوع Sqlite تحفظ العناصر وكميتها في جدول.
import sqlite3 from fastapi import FastAPI app = FastAPI() # تهيئة قاعدة البيانات def init_db(): conn = sqlite3.connect("inventory.db") cursor = conn.cursor() # إنشاء جدول البيانات إذا لم يكن موجودًا cursor.execute("CREATE TABLE IF NOT EXISTS inventory (id INTEGER PRIMARY KEY, name TEXT, quantity INTEGER)") # إضافة بيانات افتراضية إذا كانت الجدول فارغة cursor.execute("SELECT COUNT(*) FROM inventory") if cursor.fetchone()[0] == 0: sample_data = [ ("Laptop", 10), ("Keyboard", 25), ("Mouse", 30), ("Monitor", 15) ] cursor.executemany("INSERT INTO inventory (name, quantity) VALUES (?, ?)", sample_data) conn.commit() conn.close() init_db() # تهيئة كائن قاعدة البيانات # دالة لجلب العناصر الموجودة بالمخزون @app.get("/inventory") def get_inventory(): conn = sqlite3.connect("inventory.db") cursor = conn.cursor() cursor.execute("SELECT * FROM inventory") items = cursor.fetchall() conn.close() return {"inventory": items}
لتشغيل هذا التطبيق نكتب في الطرفية الأمر التالي :
uvicorn inventory_api:app --reload
بهذا تصبح واجهة التطبيق البرمجية API تعمل وجاهزة للاستخدام من خلال الرابط المحلي http://127.0.0.1:8000/inventory، أو الرابط http://127.0.0.1:8000/docs#/default/get_inventory_inventory_get الذي يسمح لنا بتجربة نقاط النهاية End-points للواجهة البرمجية API باستخدام واجهة صفحة ويب.
نوجه BlackBoxAI بعدها لتوليد ملف اختبار أداء باستخدام مكتبة Locust والتي ستسمح لنا باختبار واجهة التطبيق البرمجية API بمحاكاة استخدام عدد كبيرة من المستخدمين النظام في نفس الوقت وتساعد في تحليل أداء النظام بعرض رسومات بيانية توضح سرعة الرد وعدد مرات الفشل مقارنة بعدد الطلبات التي نفذها النظام بنجاح وغيرها من المزايا الأخرى.
from locust import HttpUser, task, between class InventoryUser(HttpUser): wait_time = between(1, 2) # كل مستخدم ينتظر بين 1-2 ثانية بين الطلبات """ inventory محاكاة أكثر من مستخدم يتصل بنقطة النهاية """ @task def load_test_inventory(self): """مستخدم افتراضي يقوم بطلب رابط inventory بشكل متكرر""" response = self.client.get("/inventory") if response.status_code != 200: response.failure("Failed to fetch inventory")
نشغل الأمر التالي من خلال الطرفية، حيث نمرر اسم الملف والرابط المحلي المؤدي للموقع.
locust -f load_test.py --host=http://127.0.0.1:8000
سنحصل على الرابط التالي http://localhost:8089 لتجربة أداة الاختبار، حيث نجد عند فتح الصفحة بعض المدخلات التي نستطيع التحكم فيها، مثل عدد المستخدمين، وتزايد ذلك العدد في كل ثانية Ramp up حيث أن أداة الاختبار تضيف هذا العدد من المستخدمين كل ثانية حتى تصل لعدد المستخدمين الأقصى بشكل تدريجي، سنضبط عدد المستخدمين ليكون 1000 مستخدم، ومعدل تزايد المستخدمين ليكون 10 في الثانية.
نرى هنا الإحصائيات المولدة في الوقت الحقيقي، حيث يرينا الرسم البياني الأول عدد الطلبات المرسلة لواجهة التطبيق البرمجية API في كل ثانية، بينما يظهر الرسم الثاني سرعة تجاوب النظام، أما الرسم الثالث فيظهر عدد المستخدمين الذي ازداد تدريجيًا حتى وصل للحد الأقصى المحدد مسبقًا، ونلاحظ أن النظام كان قادرًا على التعامل مع ألف مستخدم بسهولة ومع عدد من الطلبات يصل إلى 650 طلب في الثانية بدون أي فشل في إجابة الطلبات المرسلة للواجهة البرمجية للتطبيق API.
يمكننا تعريض النظام لمستوى أعلى من الضغط لنرى نسبة الفشل في إجابة الطلبات، بأن نجعل عدد المستخدمين 100 ألف مثلًا، يزيدون بمعدل 1000 في كل مرة، سيزيد احتمال حدوث الفشل لعجز نظامنا على التعامل مع هذا الكم من الضغط.
وصلت نسبة الفشل إلى 88% حيث فشل 332008 طلب من أصل 377561، وكان متوسط سرعة الإجابة 174 ثانية، وهذا وقت طويل يدل أن النظام لم يستطع تحمل الزيادة في الحمل، كما نرى من الرسومات البيانية الموضحة بالأعلى أن النظام بدأ في التدهور عندما تجاوز عدد المستخدمين 50 ألف تقريبًا، هذه المعلومات تمكننا من تحسين كفاءة النظام تحت الضغط بإجراءات مثل تحجيم عدد الطلبات المسموح للمستخدم إرسالها في فترة زمنية محددة، واستخدام رتل Queue لتخزين الطلبات الفائضة عن سعة النظام لتعالج عندما يستطيع النظام استيعاب المزيد من الطلبات، فبدلًا من محاولة معالجة 100 ألف طلب نستطيع تخزين الطلبات في رتل Queue وندفع الطلبات للنظام على هيئة دفعات كل دفعة تتكون من 10000 طلب فقط.
خاتمة
تعرفنا في هذا المقال على كيفية استغلال قدرات أداة الذكاء الاصطناعي BlackBoxAI لتطبيق مبادئ اختبار البرامج Software testing بأنواعها المختلفة، مثل الاختبارات الوظيفية Functional testing كاختبار الوحدة Unit test واختبار الانحدار Regression test بالإضافة للاختبارات غير الوظيفية Non-functional testing التي تركز على اختبار أداء النظام وسرعة استجابته ونقاط الفشل المحتملة للنظام عن طريق محاكاة ظروف استخدام مختلفة، حيث استطعنا توليد الشيفرة المناسبة من خلال استخدام الموجهات Prompts المناسبة في BlackBoxAI وتحسينه حسب حاجتنا لذلك.
وكما أن عملية توجيه أدوات الذكاء الاصطناعي عملية تكرارية ومستمرة فإن عملية اختبار البرامج كذلك تمر بدورات متتابعة من المحاولة والخطأ والتحسين المستمر للوصول لنسبة تغطية كافية لحالات الاختبار والحالات المتطرفة مما يضيق نطاق البحث عند وقوع أخطاء أو مشكلات في برامجنا، فيسهل اكتشافها وحلها بسرعة.

أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.