مقدمة: لماذا يُعد الاختبار أساس تطبيق Swift موثوق
يتطلب التطوير لأجهزة iOS و macOS واجهة جميلة فحسب، بل أيضًا منطقًا مستقرًا. الاختبار في Swift ليس خيارًا، بل ضرورة. بدون اختبارات، حتى التغيير الصغير يمكن أن يكسر وظائف كانت تعمل لسنوات. في هذه المقالة، سنقوم بتفصيل ثلاثة مستويات من الاختبار: الوحدة، التكامل، و e2e (من النهاية إلى النهاية). سوف تتعلم كيفية تكوينها وكتابتها وتشغيلها بشكل صحيح على منصات Apple. في النهاية — نصائح عملية لتنظيم بنية الاختبار.
المستوى 1: اختبارات الوحدة — الأساس
تفحص اختبارات الوحدة الوظائف الفردية أو الطرق أو الفئات بشكل منفصل. في Swift، الإطار الرئيسي هو XCTest. إنه مدمج في Xcode، ولا يتطلب تبعيات خارجية، ومثالي لاختبار منطق الأعمال.
كيفية كتابة أول اختبار وحدة
أنشئ هدف اختبار وحدة جديد في Xcode (File → New → Target → Unit Testing Bundle). ثم أضف فئة اختبار:
import XCTest@testable import MyApp
final class CalculatorTests: XCTestCase { var sut: Calculator! override func setUpWithError() throws { sut = Calculator() } override func tearDownWithError() throws { sut = nil } func testAddition() { // Given let a = 5 let b = 3 // When let result = sut.add(a, b) // Then XCTAssertEqual(result, 8, "Addition should be correct") }}أفضل الممارسات لاختبارات الوحدة
- العزل: كل اختبار يختبر وحدة واحدة فقط من الكود. استخدم
setUpوtearDownلإعادة تعيين الحالة. - التسمية: استخدم النمط
test[Method]_[Condition]_[ExpectedResult]. - النماذج الوهمية (Mocks) والبدائل (Stubs): للتبعيات الخارجية (الشبكة، قاعدة البيانات)، استخدم البروتوكولات واستبدلها في الاختبارات.
- التغطية: استهدف تغطية كود بنسبة 70-80%، لكن لا تطارد 100% — اختبر المسارات الحرجة.
مثال مع نموذج وهمي (Mock)
protocol NetworkServiceProtocol { func fetchData(completion: @escaping (Result<Data, Error>) -> Void)}
class MockNetworkService: NetworkServiceProtocol { var shouldReturnError = false func fetchData(completion: @escaping (Result<Data, Error>) -> Void) { if shouldReturnError { completion(.failure(NSError(domain: "test", code: 1))) } else { completion(.success(Data())) } }}
func testFetchDataSuccess() { let mock = MockNetworkService() let viewModel = ViewModel(networkService: mock) mock.shouldReturnError = false viewModel.loadData() XCTAssertTrue(viewModel.isDataLoaded)}المستوى 2: اختبارات التكامل — التحقق من التفاعلات
تتحقق اختبارات التكامل من كيفية عمل الوحدات المختلفة للنظام معًا: قاعدة البيانات + الشبكة، واجهة المستخدم + منطق الأعمال، خدمات متعددة. في Swift، يتم استخدام XCTest لهذا مع تبعيات حقيقية (أو في الذاكرة).
سيناريو نموذجي: Core Data + Network
import XCTest@testable import MyApp
class UserServiceIntegrationTests: XCTestCase { var coreDataStack: CoreDataStack! var networkService: NetworkService! var userService: UserService! override func setUp() { coreDataStack = CoreDataStack(inMemory: true) // in-memory for tests networkService = NetworkService() userService = UserService(coreDataStack: coreDataStack, networkService: networkService) } func testSaveUserFromNetwork() { // Create an expectation for the async request let expectation = self.expe