Azimjon Abdurasulov

Unit Testing & QA

Cheat Sheet'lar

Unit Testing & QA Cheat Sheet

iOS loyihalarda kod sifatini ta'minlash, XCTest va zamonaviy Swift Testing (Swift 6 / iOS 18+) frameworklari hamda Mocking bo'yicha tezkor qo'llanma.


1. XCTest Asoslari va Hayotiy Sikli

import XCTest
@testable import MyApp

final class CalculatorTests: XCTestCase {
    var sut: Calculator! // System Under Test

    // Har bir testdan oldin ishlaydi
    override func setUpWithError() throws {
        try super.setUpWithError()
        sut = Calculator()
    }

    // Har bir test tugagach xotirani tozalash uchun ishlaydi
    override func tearDownWithError() throws {
        sut = nil
        try super.tearDownWithError()
    }

    func testAddition_twoNumbers_returnsSum() {
        // Given (Berilgan shartlar)
        let a = 5
        let b = 10

        // When (Amal bajarilganda)
        let result = sut.add(a, b)

        // Then (Natija tekshiruvi)
        XCTAssertEqual(result, 15, "Yig'indi to'g'ri hisoblanmadi")
    }
}

2. XCTest Assertions (Tekshiruvlar Jadvali)

AssertionMaqsadiMisol
XCTAssertTrue(x)Shart true bo'lishini talab qiladiXCTAssertTrue(user.isValid)
XCTAssertFalse(x)Shart false bo'lishini talab qiladiXCTAssertFalse(cart.isEmpty)
XCTAssertEqual(a, b)Ikkala qiymat teng bo'lishi kerakXCTAssertEqual(items.count, 3)
XCTAssertNotEqual(a, b)Qiymatlar bir-biriga teng bo'lmasligi kerakXCTAssertNotEqual(oldToken, newToken)
XCTAssertNil(x)Obyekt nil bo'lishi kerakXCTAssertNil(error)
XCTAssertNotNil(x)Obyekt nil bo'lmasligi shartXCTAssertNotNil(result)
XCTAssertThrowsError(expr)Ifoda xatolik (throw) berishi kerakXCTAssertThrowsError(try parse(""))
XCTAssertNoThrow(expr)Hech qanday xatolik bermasligi kerakXCTAssertNoThrow(try save())

3. Asinxron Kodni Testlash

async/await bilan (Zamonaviy):

func testFetchUserProfile_success() async throws {
    let mockService = MockUserService()
    mockService.stubbedUser = User(id: 1, name: "Azimjon")
    let viewModel = ProfileViewModel(service: mockService)

    await viewModel.loadUser()

    XCTAssertEqual(viewModel.userName, "Azimjon")
}

Expectation bilan (Callback / Notification / Delegate):

func testTimerCompletes() {
    let exp = expectation(description: "Taymer tugashi kerak")

    sut.startTimer(duration: 0.1) {
        exp.fulfill()
    }

    wait(for: [exp], timeout: 1.0)
}

4. Swift Testing (Swift 6 / iOS 18+ Yangi Standart)

Apple'ning makrolarga asoslangan eng yangi deklarativ test frameworki.

import Testing
@testable import MyApp

@Suite("Foydalanuvchi hisob-kitob testlari")
struct UserTests {

    @Test("Yangi foydalanuvchi hisobi balansi 0 bo'lishi kerak")
    func initialBalanceIsZero() {
        let account = BankAccount()
        #expect(account.balance == 0)
    }

    @Test("Pul yechish yetarli mablag' bo'lmaganda xato berishi kerak")
    func withdrawInsufficientFunds() throws {
        var account = BankAccount(initial: 50)
        #expect(throws: BankError.insufficientFunds) {
            try account.withdraw(100)
        }
    }

    // Argumentlar bilan (Parameterized Tests)
    @Test("Yosh bo'yicha toifani aniqlash", arguments: [
        (age: 10, expected: "Bola"),
        (age: 16, expected: "O'smir"),
        (age: 25, expected: "Katta")
    ])
    func ageCategories(age: Int, expected: String) {
        #expect(categorize(age: age) == expected)
    }
}

5. Test Doubles (Mock, Stub, Spy, Fake)

TurTavsif
DummyShunchaki parametrni to'ldirish uchun uzatiladigan bo'sh obyekt
StubHar doim oldindan tayyorlangan aniq qiymatni qaytaruvchi soxta obyekt
SpyMetod necha marta va qanday parametrlar bilan chaqirilganini yozib boruvchi
MockChaqirilishi kutilayotgan metodlar va xatti-harakatlarni o'zida tekshiruvchi
FakeIshlaydigan yengilroq sodda implementatsiya (masalan, In-Memory DB)
// Spy & Stub Namunasi:
final class MockAuthService: AuthServiceProtocol {
    // Stub
    var loginResult: Result<User, Error> = .success(User(id: "1"))
    
    // Spy (Chaqiruvlarni kuzatish)
    private(set) var loginCallCount = 0
    private(set) var lastEmailAttempt: String?

    func login(email: String, pass: String) async throws -> User {
        loginCallCount += 1
        lastEmailAttempt = email
        return try loginResult.get()
    }
}

6. UI Testing (XCUIApplication)

final class LoginUITests: XCTestCase {
    func testLoginButtonNavigatesToHome() {
        let app = XCUIApplication()
        app.launch()

        let emailField = app.textFields["email_text_field"]
        emailField.tap()
        emailField.typeText("test@example.com")

        let loginButton = app.buttons["login_button"]
        XCTAssertTrue(loginButton.exists)
        loginButton.tap()

        let welcomeLabel = app.staticTexts["welcome_label"]
        XCTAssertTrue(welcomeLabel.waitForExistence(timeout: 2.0))
    }
}

Markdown manba

iOS Lessons