国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

UnitTesting 單元測(cè)試

這篇具有很好參考價(jià)值的文章主要介紹了UnitTesting 單元測(cè)試。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1. 測(cè)試分為兩種及詳細(xì)介紹測(cè)試書籍:

? 1.1 Unit Test : 單元測(cè)試

? - test the business logic in your app : 測(cè)試應(yīng)用中的業(yè)務(wù)邏輯

? 1.2 UI? Test :? 界面測(cè)試

? - test the UI of your app : 測(cè)試應(yīng)用中的界面

? 1.3 測(cè)試書籍網(wǎng)址:

《Testing Swift》https://www.hackingwithswift.com/store/testing-swift

2. ViewModel 單元測(cè)試

? 2.1 創(chuàng)建 ViewModel,UnitTestingBootcampViewModel.swift

import Foundation
import SwiftUI
import Combine

/// 單元測(cè)試 ViewModel
class UnitTestingBootcampViewModel: ObservableObject{
    @Published var isPremium: Bool
    @Published var dataArray: [String] = []
    @Published var selectedItem: String? = nil
    let dataService: NewDataServiceProtocol
    var cancellable = Set<AnyCancellable>()
    
    init(isPremium: Bool, dataService: NewDataServiceProtocol = NewMockDataService(items: nil)) {
        self.isPremium = isPremium
        self.dataService = dataService
    }
    
    /// 添加子項(xiàng)
    func addItem(item: String){
        // 為空不往下執(zhí)行
        guard !item.isEmpty else { return }
        self.dataArray.append(item)
    }
    
    /// 選中項(xiàng)
    func selectItem(item: String){
        if let x = dataArray.first(where: {$0 == item}){
            selectedItem = x
        }else{
            selectedItem = nil
        }
    }
    
    /// 保存項(xiàng)
    func saveItem(item: String) throws{
        guard !item.isEmpty else{
            throw DataError.noData
        }
        
        if let x = dataArray.first(where: {$0 == item}){
            print("Save item here!!! \(x)")
        } else {
            throw DataError.itemNotFound
        }
    }
    
    /// 錯(cuò)誤信息
    enum DataError: LocalizedError{
        case noData
        case itemNotFound
    }
    
    /// 請(qǐng)求返回?cái)?shù)據(jù)
    func downloadWithEscaping() {
        dataService.downloadItemsWithEscaping { [weak self] returnedItems in
            self?.dataArray = returnedItems
        }
    }
    
    /// 下載用到的組合
    func downloadWithCombine() {
        dataService.downloadItemsWithCombine()
            .sink { _ in
                
            } receiveValue: { [weak self] returnedItems in
                self?.dataArray = returnedItems
            }
            .store(in: &cancellable)
    }
}

? 2.2 創(chuàng)建測(cè)試文件

? ? 當(dāng)創(chuàng)建項(xiàng)目時(shí),沒有選擇 Include Tests/包含測(cè)試 選項(xiàng)時(shí),需要添加文件去對(duì)應(yīng)項(xiàng)目,不然測(cè)試文件會(huì)報(bào) No such module 'XCTest' 編譯錯(cuò)誤

? ? 添加單元測(cè)試文件:

? ? 方法一 : 選擇項(xiàng)目 -> 菜單欄 Editor -> Add Target... -> 彈出對(duì)話框,選擇 Test 欄下 -> Unit Testing Bundle -> 填寫信息/可默認(rèn) -> Finish,完成創(chuàng)建單元測(cè)試文件。

? ? 方法二 : 選擇項(xiàng)目,點(diǎn)擊 PROJECT 列,最下的 + 按鈕,彈出對(duì)話框,選擇 Test 欄下 ,后面步驟與上一致

? ? 創(chuàng)建單元測(cè)試文件 UnitTestingBootcampViewModel_Tests.swift文章來源地址http://www.zghlxwxcb.cn/news/detail-722630.html

import XCTest
import Combine
/// 導(dǎo)入項(xiàng)目
@testable import SwiftfulThinkingAdvancedLearning

// 《Testing Swift》 測(cè)試書籍
// 書籍網(wǎng)址: https://www.hackingwithswift.com/store/testing-swift
// Naming Structure: test_UnitOfWork_StateUnderTest_ExpectedBehavior -  結(jié)構(gòu)體命名: 測(cè)試_工作單元_測(cè)試狀態(tài)_預(yù)期的行為
// Naming Structure: test_[struct or class]_[variable or function]_[expected result] - 測(cè)試_[結(jié)構(gòu)體 或者 類的名稱]_[類中的變量名 或者 函數(shù)名稱]_[預(yù)期結(jié)果 預(yù)期值]
// Testing Structure: Given, When, Then - 測(cè)試結(jié)構(gòu): 給定,什么時(shí)候,然后

final class UnitTestingBootcampViewModel_Tests: XCTestCase {
    /// 解決多次引用相同的類
    var viewModel: UnitTestingBootcampViewModel?
    var cancellables = Set<AnyCancellable>()
    
    /// 開始設(shè)置數(shù)據(jù)
    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.
        viewModel = UnitTestingBootcampViewModel(isPremium: Bool.random())
    }
    
    /// 結(jié)束重置數(shù)據(jù)
    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        viewModel = nil
        cancellables.removeAll()
    }
    
    /// 單元測(cè)試函數(shù)名,根據(jù)命名規(guī)則命名:測(cè)試_類名稱_是否高質(zhì)量_應(yīng)該為真
    func test_UnitTestingBootcampViewModel_isPremium_shouldBeTrue(){
        // Given
        let userIsPremium: Bool = true
        
        // When
        let vm = UnitTestingBootcampViewModel(isPremium: userIsPremium)
        
        // Then
        XCTAssertTrue(vm.isPremium)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名:測(cè)試_類名稱_是否高質(zhì)量_應(yīng)該為假
    func test_UnitTestingBootcampViewModel_isPremium_shouldBeFalse(){
        // Given
        let userIsPremium: Bool = false
        
        // When
        let vm = UnitTestingBootcampViewModel(isPremium: userIsPremium)
        
        // Then
        XCTAssertFalse(vm.isPremium)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名:測(cè)試_類名稱_是否高品質(zhì)_注入值
    func test_UnitTestingBootcampViewModel_isPremium_shouldBeInjectedValue(){
        // Given
        let userIsPremium: Bool = Bool.random()
        
        // When
        let vm = UnitTestingBootcampViewModel(isPremium: userIsPremium)
        
        // Then
        XCTAssertEqual(vm.isPremium, userIsPremium)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 注入值_壓力 / for 循環(huán)
    func test_UnitTestingBootcampViewModel_isPremium_shouldBeInjectedValue_stress(){
        for _ in 0 ..< 10 {
            // Given
            let userIsPremium: Bool = Bool.random()
            // When
            let vm = UnitTestingBootcampViewModel(isPremium: userIsPremium)
            // Then
            XCTAssertEqual(vm.isPremium, userIsPremium)
        }
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 數(shù)組_預(yù)期值:為空
    func test_UnitTestingBootcampViewModel_dataArray_shouldBeEmpty(){
        // Given
        
        // When
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // Then 斷言 = 判定
        XCTAssertTrue(vm.dataArray.isEmpty)
        XCTAssertEqual(vm.dataArray.count, 0)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 數(shù)組_預(yù)期值:添加項(xiàng)
    func test_UnitTestingBootcampViewModel_dataArray_shouldAddItems(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let loopCount: Int = Int.random(in: 1..<100)
        
        for _ in 0 ..< loopCount{
            vm.addItem(item: UUID().uuidString)
        }
        
        // Then 斷言 = 判定
        XCTAssertTrue(!vm.dataArray.isEmpty)
        XCTAssertFalse(vm.dataArray.isEmpty)
        XCTAssertEqual(vm.dataArray.count, loopCount)
        XCTAssertNotEqual(vm.dataArray.count, 0)
        // GreaterThan 大于
        XCTAssertGreaterThan(vm.dataArray.count, 0)
        // XCTAssertGreaterThanOrEqual
        // XCTAssertLessThan
        // XCTAssertLessThanOrEqual
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 數(shù)組_預(yù)期值:添加空白字符
    func test_UnitTestingBootcampViewModel_dataArray_shouldNotAddBlankString(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        vm.addItem(item: "")
        
        // Then 斷言 = 判定
        XCTAssertTrue(vm.dataArray.isEmpty)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 數(shù)組_預(yù)期值:添加空白字符
    func test_UnitTestingBootcampViewModel_dataArray_shouldNotAddBlankString2(){
        // Given
        guard let vm = viewModel else {
            XCTFail()
            return
        }
        
        // When
        vm.addItem(item: "")
        
        // Then 斷言 = 判定
        XCTAssertTrue(vm.dataArray.isEmpty)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 選中項(xiàng)_預(yù)期值:開始為空
    func test_UnitTestingBootcampViewModel_selectedItem_shouldStartAsNil(){
        // Given
        
        // When
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // Then 斷言 = 判定
        XCTAssertTrue(vm.selectedItem == nil)
        XCTAssertNil(vm.selectedItem)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 選中項(xiàng)_預(yù)期值:應(yīng)該為空 當(dāng)選擇無效項(xiàng)
    func test_UnitTestingBootcampViewModel_selectedItem_shouldBeNilWhenSelectingInvalidItem(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // Select valid item : 選擇有效項(xiàng)
        let newItem = UUID().uuidString
        vm.addItem(item: newItem)
        vm.selectItem(item: newItem)
        
        // Select invalid item : 選擇無效項(xiàng)
        // When
        vm.selectItem(item: UUID().uuidString)
        
        // Then 斷言 = 判定
        XCTAssertNil(vm.selectedItem)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 選中項(xiàng)_預(yù)期值:應(yīng)該選中
    func test_UnitTestingBootcampViewModel_selectedItem_shouldBeSelected(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let newItem = UUID().uuidString
        vm.addItem(item: newItem)
        vm.selectItem(item: newItem)
        
        // Then 斷言 = 判定
        XCTAssertNotNil(vm.selectedItem)
        XCTAssertEqual(vm.selectedItem, newItem)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 選中項(xiàng)_預(yù)期值:選中_壓力測(cè)試
    func test_UnitTestingBootcampViewModel_selectedItem_shouldBeSelected_stress(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let loopCount: Int = Int.random(in: 1..<100)
        var itemsArray: [String] = []
        
        for _ in 0 ..< loopCount {
            let newItem = UUID().uuidString
            vm.addItem(item: newItem)
            itemsArray.append(newItem)
        }
        
        // 隨機(jī)取一個(gè)字符串
        let randomItem = itemsArray.randomElement() ?? ""
        // 檢查字符串不為空
        XCTAssertFalse(randomItem.isEmpty)
        vm.selectItem(item: randomItem)
        
        // Then 斷言 = 判定
        XCTAssertNotNil(vm.selectedItem)
        XCTAssertEqual(vm.selectedItem, randomItem)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 保存項(xiàng)_預(yù)期值:輸出錯(cuò)誤異常_元素沒找到
    func test_UnitTestingBootcampViewModel_saveItem_shouldThrowError_itemNotFound(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let loopCount: Int = Int.random(in: 1..<100)
        for _ in 0 ..< loopCount {
            vm.addItem(item: UUID().uuidString)
        }
        
        // Then 斷言 = 判定
        XCTAssertThrowsError(try vm.saveItem(item: UUID().uuidString))
        XCTAssertThrowsError(try vm.saveItem(item: UUID().uuidString), "Should throw Item Not Found error!") { error in
            // 返回錯(cuò)誤
            let returnedError = error as? UnitTestingBootcampViewModel.DataError
            // 判斷錯(cuò)誤是否相同
            XCTAssertEqual(returnedError, UnitTestingBootcampViewModel.DataError.itemNotFound)
        }
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 保存項(xiàng)_預(yù)期值:輸出錯(cuò)誤異常_沒數(shù)據(jù)
    func test_UnitTestingBootcampViewModel_saveItem_shouldThrowError_noData(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let loopCount: Int = Int.random(in: 1..<100)
        for _ in 0 ..< loopCount {
            vm.addItem(item: UUID().uuidString)
        }
        
        // Then 斷言 = 判定
        do {
            try vm.saveItem(item: "")
        } catch let error {
            // 返回錯(cuò)誤
            let returnedError = error as? UnitTestingBootcampViewModel.DataError
            // 判斷錯(cuò)誤是否相同
            XCTAssertEqual(returnedError, UnitTestingBootcampViewModel.DataError.noData)
        }
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 保存項(xiàng)_預(yù)期值:保存選項(xiàng)
    func test_UnitTestingBootcampViewModel_saveItem_shouldSaveItem(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let loopCount: Int = Int.random(in: 1..<100)
        var itemsArray: [String] = []
        
        for _ in 0 ..< loopCount {
            let newItem = UUID().uuidString
            vm.addItem(item: newItem)
            itemsArray.append(newItem)
        }
        
        // 隨機(jī)取一個(gè)字符串
        let randomItem = itemsArray.randomElement() ?? ""
        // 檢查字符串不為空
        XCTAssertFalse(randomItem.isEmpty)
        // Then 斷言 = 判定
        XCTAssertNoThrow(try vm.saveItem(item: randomItem))
        do {
            try vm.saveItem(item: randomItem)
        } catch  {
            XCTFail()
        }
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 下載數(shù)據(jù)_預(yù)期值:返回選項(xiàng)
    func test_UnitTestingBootcampViewModel_downloadWithEscaping_shouldReturnItems(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let expectation = XCTestExpectation(description: "Should return items after 3 seconds")
        // dropFirst: 刪除第一個(gè)發(fā)布 數(shù)組值,因?yàn)槌跏蓟癁榭諗?shù)組,取的是第二個(gè)數(shù)組,模擬服務(wù)數(shù)據(jù)返回的數(shù)組
        vm.$dataArray
            .dropFirst()
            .sink { returnedItems in
                expectation.fulfill()
            }
            .store(in: &cancellables)
        
        vm.downloadWithEscaping()
        
        // Then 斷言 = 判定 GreaterThan:大于
        // 為了安全獲取到值,設(shè)置等待 5 秒
        wait(for: [expectation], timeout: 5)
        XCTAssertGreaterThan(vm.dataArray.count, 0)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 下載數(shù)據(jù)組合_預(yù)期值:返回選項(xiàng)
    func test_UnitTestingBootcampViewModel_downloadWithCombine_shouldReturnItems(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let expectation = XCTestExpectation(description: "Should return items after a seconds")
        // dropFirst: 刪除第一個(gè)發(fā)布 數(shù)組值,因?yàn)槌跏蓟癁榭諗?shù)組,取的是第二個(gè)數(shù)組,模擬服務(wù)數(shù)據(jù)返回的數(shù)組
        vm.$dataArray
            .dropFirst()
            .sink { returnedItems in
                expectation.fulfill()
            }
            .store(in: &cancellables)
        
        vm.downloadWithCombine()
        
        // Then 斷言 = 判定 GreaterThan:大于
        // 為了安全獲取到值,設(shè)置等待 5 秒
        wait(for: [expectation], timeout: 5)
        XCTAssertGreaterThan(vm.dataArray.count, 0)
    }
    
    /// 單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 下載數(shù)據(jù)組合_預(yù)期值:返回選項(xiàng)
    func test_UnitTestingBootcampViewModel_downloadWithCombine_shouldReturnItems2(){
        // Given
        let items: [String] = [UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString]
        let dataService: NewDataServiceProtocol = NewMockDataService(items: items)
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random(), dataService: dataService)
        
        // When
        let expectation = XCTestExpectation(description: "Should return items after a seconds")
        // dropFirst: 刪除第一個(gè)發(fā)布 數(shù)組值,因?yàn)槌跏蓟癁榭諗?shù)組,取的是第二個(gè)數(shù)組,模擬服務(wù)數(shù)據(jù)返回的數(shù)組
        vm.$dataArray
            .dropFirst()
            .sink { returnedItems in
                expectation.fulfill()
            }
            .store(in: &cancellables)
        
        vm.downloadWithCombine()
        
        // Then 斷言 = 判定 GreaterThan:大于
        // 為了安全獲取到值,設(shè)置等待 5 秒
        wait(for: [expectation], timeout: 5)
        XCTAssertGreaterThan(vm.dataArray.count, 0)
        XCTAssertEqual(vm.dataArray.count, items.count)
    }
}

3. 模擬請(qǐng)求數(shù)據(jù) 單元測(cè)試

? 3.1 創(chuàng)建模擬請(qǐng)求數(shù)據(jù)類 NewMockDataService.swift

import Foundation
import SwiftUI
import Combine

/// 定義協(xié)議
protocol NewDataServiceProtocol{
    func downloadItemsWithEscaping(completion: @escaping (_ items: [String]) -> ())
    func downloadItemsWithCombine() -> AnyPublisher<[String], Error>
}

/// 實(shí)現(xiàn)模擬請(qǐng)求數(shù)據(jù)
class NewMockDataService: NewDataServiceProtocol {
    let items: [String]
    
    init(items: [String]?) {
        self.items = items ?? [
            "ONE", "TWO", "THREE"
        ]
    }
    
    /// 模擬網(wǎng)絡(luò)下載數(shù)據(jù) escaping: 轉(zhuǎn)義字符
    func downloadItemsWithEscaping(completion: @escaping (_ items: [String]) -> ()) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            completion(self.items)
        }
    }
    
    /// 下載組合
    func downloadItemsWithCombine() -> AnyPublisher<[String], Error> {
        // 數(shù)據(jù)轉(zhuǎn)換
        Just(self.items)
            .tryMap({ publishedItems in
                guard !publishedItems.isEmpty else {
                    throw URLError(.badServerResponse)
                }
                return publishedItems
            })
            .eraseToAnyPublisher()
    }
}

? 3.2 創(chuàng)建單元測(cè)試類 NewMockDataService_Tests.swift

import XCTest
import Combine
/// 導(dǎo)入項(xiàng)目
@testable import SwiftfulThinkingAdvancedLearning

final class NewMockDataService_Tests: XCTestCase {
    /// 隨時(shí)取消控制器
    var cancellable = Set<AnyCancellable>()
    
    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        cancellable.removeAll()
    }
    
    //  單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 測(cè)試_類名_初始化_預(yù)期值:正確的設(shè)置值
    func test_NewMockDataService_init_doesSetValuesCorrectly() {
        // 執(zhí)行
        // Given: 給定
        let items: [String]? = nil
        let items2: [String]? = []
        let items3: [String]? = [UUID().uuidString, UUID().uuidString]
        
        // When: 時(shí)間
        let dataService = NewMockDataService(items: items)
        let dataService2 = NewMockDataService(items: items2)
        let dataService3 = NewMockDataService(items: items3)
        
        // Then 然后
        XCTAssertFalse(dataService.items.isEmpty)
        XCTAssertTrue(dataService2.items.isEmpty)
        XCTAssertEqual(dataService3.items.count, items3?.count)
    }
    
    //  單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 測(cè)試_類名_下載轉(zhuǎn)換數(shù)據(jù)項(xiàng)_預(yù)期值:正確的設(shè)置值
    func test_NewMockDataService_downloadItemsWithEscaping_doesReturnValues() {
        // 執(zhí)行
        // Given: 給定
        let dataService = NewMockDataService(items: nil)
        
        // When: 時(shí)間
        var items: [String] = []
        let expectation = XCTestExpectation()
        dataService.downloadItemsWithEscaping { returnedItems in
            items = returnedItems
            expectation.fulfill()
        }
        
        // Then 然后
        // 等待 5 秒
        wait(for: [expectation], timeout: 5)
        // 斷言兩個(gè)數(shù)組大小一樣
        XCTAssertEqual(items.count, dataService.items.count)
    }
    
    //  單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 測(cè)試_類名_下載數(shù)據(jù)項(xiàng)組合_預(yù)期值:正確的設(shè)置值
    func test_NewMockDataService_downloadItemsWithCombine_doesReturnValues() {
        // 執(zhí)行
        // Given: 給定
        let dataService = NewMockDataService(items: nil)
        
        // When: 時(shí)間
        var items: [String] = []
        let expectation = XCTestExpectation()
        
        // 下載組合控制
        dataService.downloadItemsWithCombine()
            .sink { completion in
                switch completion{
                case .finished:
                    expectation.fulfill()
                case .failure:
                    XCTFail()
                }
            } receiveValue: {returnedItems in
                // fulfill: 完成
                items = returnedItems
            }
            .store(in: &cancellable)
        // Then 然后
        // 等待 5 秒
        wait(for: [expectation], timeout: 5)
        // 斷言兩個(gè)數(shù)組大小一樣
        XCTAssertEqual(items.count, dataService.items.count)
    }
    
    //  單元測(cè)試函數(shù)名 根據(jù)命名規(guī)則命名 - 測(cè)試_類名_下載數(shù)據(jù)項(xiàng)組合_預(yù)期值:確實(shí)失敗
    func test_NewMockDataService_downloadItemsWithCombine_doesFail() {
        // 執(zhí)行
        // Given: 給定
        let dataService = NewMockDataService(items: [])
        
        // When: 時(shí)間
        var items: [String] = []
        let expectation = XCTestExpectation(description: "Does throw an error")
        let expectation2 = XCTestExpectation(description: "Does throw URLError.badServerResponse")
        // 下載組合控制
        dataService.downloadItemsWithCombine()
            .sink { completion in
                switch completion{
                case .finished:
                    XCTFail()
                case .failure(let error):
                    expectation.fulfill()
                    
                    //let urlError = error as? URLError
                    // 斷言,判定
                    //XCTAssertEqual(urlError, URLError(.badServerResponse))
                    
                    // 錯(cuò)誤判斷
                    if error as? URLError == URLError(.badServerResponse) {
                        expectation2.fulfill()
                    }
                }
            } receiveValue: {returnedItems in
                // fulfill: 完成
                items = returnedItems
            }
            .store(in: &cancellable)
        // Then 然后
        // 等待 5 秒
        wait(for: [expectation, expectation2], timeout: 5)
        // 斷言兩個(gè)數(shù)組大小一樣
        XCTAssertEqual(items.count, dataService.items.count)
    }
}

4. 創(chuàng)建單元測(cè)試 View,調(diào)用測(cè)試的 ViewModel UnitTestingBootcampView.swift

import SwiftUI

/*
 1. Unit Test : 單元測(cè)試
 - test the business logic in your app : 測(cè)試應(yīng)用中的業(yè)務(wù)邏輯
 
 2. UI  Test :  界面測(cè)試
 - test the UI of your app : 測(cè)試應(yīng)用中的界面
 */

/// 單元測(cè)試
struct UnitTestingBootcampView: View {
    @StateObject private var vm: UnitTestingBootcampViewModel
    
    init(isPremium: Bool){
        _vm = StateObject(wrappedValue: UnitTestingBootcampViewModel(isPremium: isPremium))
    }
    
    var body: some View {
        Text(vm.isPremium.description)
    }
}

struct UnitTestingBootcampView_Previews: PreviewProvider {
    static var previews: some View {
        UnitTestingBootcampView(isPremium: true)
    }
}

到了這里,關(guān)于UnitTesting 單元測(cè)試的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Swift SwiftUI 隱藏鍵盤

    Swift SwiftUI 隱藏鍵盤

    如果僅支持 iOS 15 及更高版本,則可以通過聚焦和取消聚焦來激活和關(guān)閉文本字段的鍵盤。 在最簡單的形式中,這是使用 @FocusState 屬性包裝器和 focusable() 修飾符完成的-第一個(gè)存儲(chǔ)一個(gè)布爾值,用于跟蹤第二個(gè)當(dāng)前是否被聚焦。 熊貓小賬本 一個(gè)簡潔的記賬 App,用于記錄日常

    2024年02月07日
    瀏覽(23)
  • swiftUI和swift的區(qū)別

    swiftUI和swift的區(qū)別

    SwiftUI是蘋果公司推出的一種用于構(gòu)建iOS、macOS、watchOS和tvOS應(yīng)用程序界面的框架。它是基于Swift編程語言開發(fā)的,旨在簡化UI開發(fā)過程并提供實(shí)時(shí)預(yù)覽功能,使開發(fā)人員可以更快地構(gòu)建出漂亮的應(yīng)用程序界面。 Swift是蘋果公司推出的一種面向?qū)ο蟮木幊陶Z言,旨在取代Objective

    2024年02月12日
    瀏覽(18)
  • SwiftUI Swift CoreData 計(jì)算某實(shí)體某屬性總和

    SwiftUI Swift CoreData 計(jì)算某實(shí)體某屬性總和

    有一個(gè)名為 Item 的實(shí)體,它有一個(gè)名為 amount 的 Double 屬性,向你的 View 添加一個(gè)計(jì)算屬性: 熊貓小賬本 一個(gè)簡潔的記賬 App,用于記錄日常消費(fèi)開支收入,使用 iCloud 保存同步數(shù)據(jù)。 支持備注,自定義時(shí)間偶爾忘記記賬也沒關(guān)系。 搜索歷史記賬,支持分類、金額、備注。 啟

    2024年02月07日
    瀏覽(20)
  • iOS 單元測(cè)試

    iOS 單元測(cè)試

    作用一名合格的程序員,得能文能武。寫的了代碼,也要寫的了單元測(cè)試。 單元測(cè)試步驟 1.File - New - Target, 選擇單元測(cè)試Target,創(chuàng)建成功 如果項(xiàng)目是老項(xiàng)目,那需要手動(dòng)創(chuàng)建一下UnitTest Target,如果項(xiàng)目里已經(jīng)有了就忽略。 2.創(chuàng)建一個(gè)swift工具的測(cè)試類CalculatorTests 然后就可以在

    2024年02月03日
    瀏覽(18)
  • swift - 如何在數(shù)組大小更改后刷新 ForEach 顯示元素的數(shù)量(SwiftUI、Xcode 11 Beta 5)

    swift - 如何在數(shù)組大小更改后刷新 ForEach 顯示元素的數(shù)量(SwiftUI、Xcode 11 Beta 5)

    我正在嘗試實(shí)現(xiàn)一個(gè) View ,該 View 可以在內(nèi)容數(shù)組的大小發(fā)生變化時(shí)更改顯示項(xiàng)目的數(shù)量(由 ForEach 循環(huán)創(chuàng)建),就像購物應(yīng)用程序可能會(huì)在用戶下拉刷新后更改其可用項(xiàng)目的數(shù)量一樣 這是我到目前為止嘗試過的一些代碼。如果我沒記錯(cuò)的話,這些適用于 Xcode beta 4,但適用于

    2024年02月14日
    瀏覽(21)
  • iOS 單元測(cè)試之常用框架 OCMock 詳解

    iOS 單元測(cè)試之常用框架 OCMock 詳解

    測(cè)試驅(qū)動(dòng)開發(fā)并不是一個(gè)很新鮮的概念了。在日常開發(fā)中,很多時(shí)候需要測(cè)試,但是這種輸出是必須在點(diǎn)擊一系列按鈕之后才能在屏幕上顯示出來的東西。測(cè)試的時(shí)候,往往是用模擬器一次一次的從頭開始啟動(dòng) app,然后定位到自己所在模塊的程序,做一系列的點(diǎn)擊操作,然后

    2024年02月09日
    瀏覽(18)
  • 在Bamboo上怎么使用iOS的單元測(cè)試

    作者:京東零售?吳滔 本教程將使用北汽登錄模塊為例,一步一步和大家一起搭建單元測(cè)試用例,并在Bamboo上跑起來,最終測(cè)試結(jié)果和代碼覆蓋率會(huì)Bamboo上匯總。 模塊名稱:BQLoginModule,是通過iBiu創(chuàng)建的一個(gè)模塊工程 ProductName: BQLoginTests 如果我們要在測(cè)試代碼使用我們?cè)赑od里的

    2024年02月03日
    瀏覽(13)
  • iOS 單元測(cè)試之常用框架 OCMock 詳解 | 京東云技術(shù)團(tuán)隊(duì)

    iOS 單元測(cè)試之常用框架 OCMock 詳解 | 京東云技術(shù)團(tuán)隊(duì)

    1.1 單元測(cè)試的必要性 測(cè)試驅(qū)動(dòng)開發(fā)并不是一個(gè)很新鮮的概念了。在日常開發(fā)中,很多時(shí)候需要測(cè)試,但是這種輸出是必須在點(diǎn)擊一系列按鈕之后才能在屏幕上顯示出來的東西。測(cè)試的時(shí)候,往往是用模擬器一次一次的從頭開始啟動(dòng) app,然后定位到自己所在模塊的程序,做一

    2024年02月09日
    瀏覽(19)
  • 關(guān)于iOS:如何使用SwiftUI調(diào)整圖片大小?

    關(guān)于iOS:如何使用SwiftUI調(diào)整圖片大???

    我在Assets.xcassets中擁有很大的形象。 如何使用SwiftUI調(diào)整圖像大小以縮小圖像? 我試圖設(shè)置框架,但不起作用: 1 2 Image(room.thumbnailImage) ? ? .frame(width: 32.0, height: 32.0) 在Image上應(yīng)用任何大小修改之前,應(yīng)使用.resizable()。 1 2 Image(room.thumbnailImage).resizable() .frame(width: 32.0, height: 3

    2024年02月05日
    瀏覽(19)
  • One-to-N & N-to-One: Two Advanced Backdoor Attacks Against Deep Learning Models

    One-to-N & N-to-One: Two Advanced Backdoor Attacks Against Deep Learning Models

    ? 1對(duì)N: 通過控制同一后門的不同強(qiáng)度觸發(fā)多個(gè)后門 N對(duì)1: 只有當(dāng)所有N個(gè)后門都滿足時(shí)才會(huì)觸發(fā)這種攻擊 弱攻擊模型(本論文): 不了解DNN模型的參數(shù)和架構(gòu),只知道一小部分訓(xùn)練數(shù)據(jù) ? 背景: 現(xiàn)有的研究都集中在攻擊單個(gè)后門觸發(fā)的單一目標(biāo)。 摘要 ??近年來,深度

    2024年02月08日
    瀏覽(47)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包