简体   繁体   English

如何为我的 ViewModel 编写好的测试? (RxSwift)

[英]How to writ good test for my ViewModel? (RxSwift)

I wrote some tests for my ViewModel.我为我的 ViewModel 编写了一些测试。 I use RxSwift in this project.我在这个项目中使用 RxSwift。 I have never before write unit tests, so i want to ask you about correctness of them.我以前从未写过单元测试,所以我想问你关于它们的正确性。 What can I do better next time?下次我能做些什么更好? It is little difficult for me when I write tests while I use RxSwift.当我使用 RxSwift 编写测试时,这对我来说并不困难。 All tests passed, but I don't know if they are "good tests".所有测试都通过了,但我不知道它们是否是“好的测试”。 Thanks for your help.谢谢你的帮助。

ViewModel:视图模型:

class SettingsViewModel {
private let storage = Storage.shared
private let disposeBag = DisposeBag()
let userSettings = BehaviorRelay<UserSettings>(value: UserSettings(name: "", tags: []))

init() {
    subscribe()
}

private func subscribe() {
    storage.currentUserSettings()
        .subscribe(onNext: { settings in
            if let settings = settings {
                self.userSettings.accept(settings)
            }
        })
        .disposed(by: disposeBag)
}

func saveName(_ name: String) {
    saveSettings(name: name, tags: userSettings.value.tags)
}

func addTag(_ tag: String) {
    let newTags = userSettings.value.tags + [tag]
    saveSettings(name: userSettings.value.name, tags: newTags)
}

func removeTag(_ index: Int) {
    var newTags = userSettings.value.tags
    newTags.remove(at: index)
    saveSettings(name: userSettings.value.name, tags: newTags)
}

private func saveSettings(name: String, tags: [String]) {
    let newSettings = UserSettings(name: name, tags: tags)
    Storage.shared.saveUserSettings(newSettings)
}

} }

Test class:测试class:

class SettingsViewModelTests: XCTestCase {

func test_userSettingsSaving_includesAddingName() {
    let sut = SettingsViewModel()
    let userSettings = UserSettingsSpy(sut.userSettings)
    
    sut.saveName("George")
    XCTAssertEqual(userSettings.settings.name, "George")
    
    sut.saveName("Mike")
    XCTAssertEqual(userSettings.settings.name, "Mike")
}

func test_userSettingsSaving_includesAddingTag() {
    let sut = SettingsViewModel()
    let userSettings = UserSettingsSpy(sut.userSettings)
    
    sut.addTag("Book")
    
    var savedTags: [String] = []
    Storage.shared.currentUserSettings()
        .subscribe(onNext: { settings in
            if let tags = settings?.tags {
                savedTags = tags
            }
        })
        .dispose()
    
    XCTAssertEqual(userSettings.settings.tags, savedTags)
}

func test_userSettingsSaving_includesRemovingTag() {
    let sut = SettingsViewModel()
    let userSettings = UserSettingsSpy(sut.userSettings)
    
    sut.addTag("TestTagToRemove")
    sut.removeTag(0)
    
    var savedTags: [String] = []
    Storage.shared.currentUserSettings()
        .subscribe(onNext: { settings in
            if let tags = settings?.tags {
                savedTags = tags
            }
        })
        .dispose()
    
    XCTAssertEqual(userSettings.settings.tags, savedTags)
}

class UserSettingsSpy {
    private let disposeBag = DisposeBag()
    private(set) var settings = UserSettings(name: "", tags: [])
    
    init(_ observable: BehaviorRelay<UserSettings>) {
        observable
            .subscribe(onNext: { settings in
                self.settings = settings
            })
            .disposed(by: disposeBag)
    }
}

} }

An easy way to check the correctness of your tests is to change the system under test and see if your tests flag the error.检查测试正确性的一种简单方法是更改被测系统并查看您的测试是否标记了错误。 If they don't, then that is a hole in your tests.如果他们不这样做,那么这就是您测试中的一个漏洞。 For example, the following view model will pass your tests:例如,以下视图 model 将通过您的测试:

struct Storage {
    static let shared = Storage()
    func currentUserSettings() -> Observable<UserSettings?> { .just(nil) }
}

struct SettingsViewModel {
    let userSettings = BehaviorRelay<UserSettings>(value: UserSettings())
    
    func saveName(_ value: String) {
        userSettings.accept(UserSettings(name: value, tags: []))
    }
    
    func addTag(_ value: String) { }
    
    func removeTag(_ value: Int) { }
}

struct UserSettings {
    var name: String = ""
    var tags: [String] = []
}

The code above is obviously missing some important functionality which means your tests are incomplete.上面的代码显然缺少一些重要的功能,这意味着您的测试不完整。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM