لجعل Xcode يبرز الاختبار الذي استدعى مساعدة XCTest مشتركة، أضف إلى المساعدة معاملي #filePath و#line بقيم افتراضية، ومرّرهما إلى التأكيدات. يشرح هذا الدليل الإصلاح والمساعدات المتداخلة وما يقابله في Swift Testing.
لماذا يبرز Xcode المساعدة؟
يضيف التأكيد المشترك موضعًا آخر في المصدر. يستدعي الاختبار مساعدتك، وتستدعي المساعدة تأكيدًا من XCTest. إذا استخدم هذا التأكيد وسيطات الموضع الافتراضية، فسيكون الموضع المُبلّغ عنه هو موضع التأكيد داخل المساعدة. توثّق Apple معاملي file: StaticString = #filePath وline: UInt = #line لكل من XCTAssertEqual وXCTFail.
التقط موضع المستدعي عند حدّ المساعدة، ثم مرّر هذه القيم إلى الأمام. تلتقط القيم الافتراضية لموضع المصدر في Swift موضع الاستدعاء؛ وتشرح وثيقة مشروع Swift هذا السلوك في SE-0274: أسماء ملفات سحرية موجزة. كما تعرض Apple نمط مساعدة XCTest هذا تحديدًا في الترحيل إلى Swift Testing، موضحةً كيف ينسب Xcode الإخفاق إلى استدعاء المساعدة.
بالنسبة إلى مطوّر يعمل على Mac باستخدام Xcode، تتمثل المهمة العملية في الحفاظ على الفحوصات القابلة لإعادة الاستخدام مع جعل كل إخفاق يقود إلى مدخلات الاختبار ذات الصلة. تستخدم الأمثلة أدناه مصفوفات صغيرة من الأعداد الصحيحة فقط. ولا تحتاج عند تشغيلها إلى نموذج للتطبيق أو بديل لخدمة أو اعتماد مُنزّل أو اتصال بالشبكة.
أضف معاملي موضع المستدعي إلى مساعدة XCTest
استخدم هدف اختبارات وحدة موجودًا على macOS. إذا كان المشروع يحتاج إلى واحد، فاختر File > New > Target، ثم صفِّ النتائج حسب Test واختر Unit Testing Bundle. لإضافة ملف اختبار، اختر File > New > New File From Template ثم اختر XCTest Unit Test. هذه هي المسارات التي توثقها Apple في إضافة اختبارات إلى مشروع Xcode.
ضع ملف الاختبار الكامل هذا في هدف اختبارات الوحدة. يقدّم الاختبار الثاني عمدًا مجموعًا متوقعًا غير صحيح لتتمكن من فحص موضع الإخفاق.
import XCTest
private func assertTotal(
_ values: [Int],
equals expected: Int,
file: StaticString = #filePath,
line: UInt = #line
) {
let actual = values.reduce(0, +)
XCTAssertEqual(
actual,
expected,
"Unexpected total for \(values)",
file: file,
line: line
)
}
final class TotalHelperTests: XCTestCase {
func testMatchingTotal() {
assertTotal([2, 3, 4], equals: 9)
}
func testDeliberatelyIncorrectTotal() {
assertTotal([2, 3, 4], equals: 10)
}
}
العناصر المهمة هي أنواع المعاملات وقيمها الافتراضية وتمريرها الصريح. يتوافق StaticString وUInt مع توقيع تأكيد XCTest. أبقِ #filePath و#line مباشرةً في القيم الافتراضية للمساعدة. بعد ذلك يستدعي الاختبار المساعدة دون تمرير أي من معاملي الموضع يدويًا. راجع معاملات XCTAssertEqual الموثقة.
الحساب توضيحي: 2 + 3 + 4 يساوي 9، لذا تتطابق المقارنة الأولى ولا تتطابق الثانية. تحققت من هذه الحالات الحسابية محليًا باستخدام Python. لم يكن ملف Swift التنفيذي متاحًا في بيئة البحث، لذا راجعت أمثلة Swift، لكنني لم أترجمها أو أشغّلها هنا.
تحقّق من الموضع ونتيجة الاختبار
اختر Product > Test، أو شغّل الاختبار منفردًا باستخدام زر التشغيل بجانب تعريفه. بعد ذلك، حدّد الاختبار الفاشل في Test navigator وافحص التشخيص. تصف Apple عناصر التحكم هذه وتفاصيل الإخفاق في تشغيل الاختبارات وتفسير النتائج.
تحقّق في هذا المثال من نتيجتين منفصلتين: يفشل testDeliberatelyIncorrectTotal()، ويشير تشخيص التأكيد فيه إلى استدعاء assertTotal([2, 3, 4], equals: 10). يستند إسناد الإخفاق إلى المستدعي إلى نمط التمرير الذي تعرضه Apple. بعد التحقق، غيّر 10 إلى 9 وأعِد تشغيل الاختبارات؛ ينبغي إزالة عدم التطابق المتعمد من مجموعة الاختبارات النهائية.
إذا ظل التشخيص يشير إلى موضع داخل المساعدة، فافحص استدعاء التأكيد الأخير. لا يكفي تعريف معاملي الموضع إذا أغفلت المساعدة file: file أو line: line عند تسجيل الإخفاق.
احتفظ بالموضع عبر كل طبقات المساعدات
تحتاج المساعدات المتداخلة إلى التمرير الصريح نفسه. افترض أن اختبارًا يستدعي مساعدة خاصة بالمجال، ثم تستدعي هذه المساعدة مساعدة تأكيد أدنى مستوى. إذا أغفلت المساعدة الخارجية تمرير معاملي الموضع، فستلتقط المساعدة الأدنى مستوى موضع الاستدعاء الوسيط.
هذا حدّ لغوي يجدر التحقق منه: لا تنتقل القيم الافتراضية لموضع المصدر تلقائيًا عبر استدعاءات المساعدات العشوائية. تناقش SE-0285: تسهيل الانتقال إلى سلاسل الملفات السحرية الموجزة صراحةً عدم انتقال هذه القيم بصورة متعدية.
الملف التالي بديل كامل للاختبار. وهو يوضح استدعاء مساعدة لمساعدة أخرى مع الحفاظ على موضع الاختبار الأصلي.
import XCTest
private func assertIntegerEqual(
_ actual: Int,
_ expected: Int,
file: StaticString = #filePath,
line: UInt = #line
) {
XCTAssertEqual(actual, expected, file: file, line: line)
}
private func assertRowTotal(
_ row: [Int],
equals expected: Int,
file: StaticString = #filePath,
line: UInt = #line
) {
assertIntegerEqual(
row.reduce(0, +),
expected,
file: file,
line: line
)
}
final class NestedTotalHelperTests: XCTestCase {
func testRowTotal() {
assertRowTotal([2, 3, 4], equals: 9)
}
}
استخدم تمرين تتبّع بسيطًا عند مراجعة سلسلة أطول من المساعدات: ابدأ من استدعاء الاختبار، واتبع كل مساعدة، وتأكد من وصول الموضع الملتقط نفسه إلى التأكيد. التقط القيم الافتراضية عند الحد الذي تريد ظهوره في النتيجة؛ ومرّر القيم الموجودة عبر الطبقات المتبقية. تجنّب إخفاء الالتقاط خلف دالة أخرى مستخدمة كوسيط افتراضي، وهي المشكلة التي يوضحها SE-0285.
هل يؤدي تسجيل الإخفاق إلى إيقاف الاختبار المستدعي؟
إسناد الإخفاق والتحكم في تدفق التنفيذ قراران منفصلان. تكون القيمة الافتراضية لـcontinueAfterFailure في XCTest هي true، لذا يسمح التأكيد الفاشل عادةً بمتابعة التنفيذ. ولا يغيّر تعديل الملف والسطر المُبلّغ عنه هذه الخاصية. توثّق Apple هذا السلوك في continueAfterFailure.
إذا اكتشفت المساعدة حالة تجعل بقية عملها غير صالحة، فأضف إليها مسار خروج صريحًا. على سبيل المثال، سجّل الإخفاق باستخدام الموضع الممرّر، ثم أعد من المساعدة. تذكّر أن العودة من المساعدة تعيد التحكم إلى المستدعي؛ لذا صمّم العمل الذي يتبع ذلك في المستدعي بما يلائم هذه الحالة. يعرض دليل الترحيل من Apple إخفاقًا غير مشروط يتبعه أمر عودة.
أبقِ التحقق الأول متزامنًا وصغيرًا. تأكد أولًا من أن حسابًا غير صحيح عمدًا يفشل عند موضع الاستدعاء المتوقع قبل إضافة إعداد أكثر تعقيدًا أو سلوك غير متزامن. وبهذا التسلسل يمكنك التمييز بين خلل تمرير الموضع ومشكلات تنفيذ الاختبار الأخرى.
استخدم موضع مصدر مدعومًا في Swift Testing
بالنسبة إلى مساعدة تستدعيها اختبارات Swift Testing، استخدم #expect مع SourceLocation صريح. توثّق Apple أن sourceLocation هو الموضع الذي تُنسب إليه التوقعات والمشكلات، وتذكر أن الشرط الخاطئ يسجّل مشكلة للاختبار الجاري ضمن المهمة الحالية. راجع expect(_:_:sourceLocation:).
يتطلب هذا الملف البديل الكامل Swift Testing، المتاح مع Xcode 16 وSwift 6.0. وهو يلتقط مكونات الموضع الأربعة كقيم افتراضية منفصلة، ثم ينشئ SourceLocation باستخدام المهيئ الموثق.
import Testing
private func expectTotal(
_ values: [Int],
equals expected: Int,
fileID: String = #fileID,
filePath: String = #filePath,
line: Int = #line,
column: Int = #column
) {
let location = SourceLocation(
fileID: fileID,
filePath: filePath,
line: line,
column: column
)
let actual = values.reduce(0, +)
#expect(actual == expected, sourceLocation: location)
}
@Test func matchingTotal() {
expectTotal([2, 3, 4], equals: 9)
}
@Test func deliberatelyIncorrectTotal() {
expectTotal([2, 3, 4], equals: 10)
}
يتطلب المهيئ معرّف ملف غير فارغ ومنسقًا على نحو صحيح، وأرقام أسطر وأعمدة موجبة. يجنّب التقاط المكونات التي يوفرها المترجم اختلاق هذه القيم. عند تداخل هذه المساعدات، مرّر المعاملات الأربعة الملتقطة كلها، كما يفعل إصدار XCTest عند تمرير معامليه. ومرة أخرى، صحّح التوقع المتعمد 10 بعد التحقق من الإسناد.
ما الذي يتغير عند مشاركة XCTest وSwift Testing لمساعدة؟
يمكن أن يتعايش الإطاران في حزمة اختبارات واحدة، لكن المساعدة التي تتخطى حدود الإطارين تحتاج إلى معالجة تراعي الإصدار. يوثّق دليل الترحيل الحالي من Apple قابلية التشغيل البيني والقيم الافتراضية: تستخدم سلاسل الأدوات الأقدم من Swift 6.4 القيمة none؛ أما Swift 6.4 أو الإصدارات الأحدث فتستخدم افتراضيًا limited للحزم التي تعلن عن إصدار أدوات أقدم، وcomplete للحزم التي تعلن عن إصدار أدوات 6.4 أو أحدث.
| وضع قابلية التشغيل البيني | إخفاق تأكيد XCTest داخل اختبار Swift Testing |
|---|---|
none |
يتم تجاهل المشكلة العابرة للمكتبات |
limited |
يُبلّغ عنها كتحذير مع إرشادات للتحديث |
complete |
تحتفظ بمستوى خطورة الإخفاق مع إرشادات للتحديث |
strict |
يُبلّغ عنها باستخدام fatalError |
توضح هذه الأوضاع سبب احتمال أن تسجّل المساعدة النص الصحيح، بينما يظل اختبار Swift Testing ناجحًا. تعرض جلسة الترحيل WWDC26 من Apple هذه النتيجة تحديدًا، ثم تغيّر إعداد قابلية التشغيل البيني لخطة الاختبار ضمن Test Execution إلى Complete للحفاظ على مستوى خطورة الإخفاق. تحقّق من سلسلة الأدوات المثبّتة لديك قبل الاعتماد على هذه الميزة.
في سلاسل الأدوات الأقدم، اجعل الإبلاغ عن التأكيدات خاصًا بكل إطار، وشارك الحساب الحتمي الموجود في الأسفل. أما في إعدادات قابلية التشغيل البيني المدعومة، فتعرض Apple أيضًا استبدال XCTFail في المساعدة بـIssue.record من Swift Testing. ويظل الحفاظ على تمرير موضع المصدر ضروريًا أثناء هذا الترحيل.
شخّص الأعراض المتبقية
| ما تلاحظه | ما الذي تفحصه بعد ذلك |
|---|---|
| يشير الإخفاق إلى داخل مساعدة التأكيد | تأكد من أن التأكيد يتلقى معاملي الموضع الملتقطين |
| يشير الإخفاق إلى داخل مساعدة خارجية | تأكد من أن المساعدة الخارجية تمرّر موضع مستدعيها |
| ينجح اختبار Swift Testing رغم إخفاق تأكيد XCTest | تحقّق من دعم سلسلة الأدوات ووضع قابلية التشغيل البيني |
| يستمر تنفيذ الشيفرة بعد إخفاق تأكيد XCTest | تحقّق من تدفق التنفيذ المقصود ومن continueAfterFailure |
| لا يظهر اختبار المثال ضمن التشغيل | تأكد من أن الملف تابع لهدف اختبارات الوحدة وأن خطة الاختبار النشطة تتضمنه |
للتعرّف على الاختبارات واختيارها، يشرح دليل إعداد الاختبارات ودليل تنفيذ الاختبارات من Apple أهداف الاختبار والخطط النشطة. عند إجراء تمرير بين إطارين، ارجع إلى قواعد قابلية التشغيل البيني الموثقة أعلاه قبل تغيير معاملات الموضع.
تحافظ المساعدة المشتركة المفيدة على ثلاثة أمور: مقارنة ذات معنى، وتشخيص مرتبط بالمستدعي المقصود، ونتيجة الاختبار المطلوبة. تحقّق منها باستخدام عدم تطابق متعمد واحد، ثم أزله، وواصل تمرير الموضع الملتقط كلما أُضيفت طبقة أخرى من المساعدات.
المصادر
- XCTAssertEqual(::_:file:line:) — Apple
- XCTFail(_:file:line:) — Apple
- إضافة اختبارات إلى مشروع Xcode — Apple
- تشغيل الاختبارات وتفسير النتائج — Apple
- continueAfterFailure — Apple
- ترحيل اختبار من XCTest — Apple
- التوقعات: expect(::sourceLocation:) — Apple
- init(fileID:filePath:line:column:) — Apple
- الترحيل إلى Swift Testing — Apple
- أسماء ملفات سحرية موجزة — مشروع Swift
- تسهيل الانتقال إلى سلاسل الملفات السحرية الموجزة — مشروع Swift