如何为我的 ViewModel 编写好的测试? (RxSwift)
How to writ good test for my ViewModel? (RxSwift)
我为我的 ViewModel 编写了一些测试。我在这个项目中使用 RxSwift。我以前从未写过单元测试,所以我想问你关于它们的正确性。下次我可以做些什么更好?当我使用 RxSwift 编写测试时,这对我来说并不困难。所有测试都通过了,但我不知道它们是否是“好的测试”。感谢您的帮助。
视图模型:
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)
}
}
测试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)
}
}
}
检查测试正确性的一种简单方法是更改被测系统并查看您的测试是否标记了错误。如果他们不这样做,那么这就是您测试中的一个漏洞。例如,以下视图模型将通过您的测试:
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] = []
}
上面的代码显然缺少一些重要的功能,这意味着您的测试不完整。
我为我的 ViewModel 编写了一些测试。我在这个项目中使用 RxSwift。我以前从未写过单元测试,所以我想问你关于它们的正确性。下次我可以做些什么更好?当我使用 RxSwift 编写测试时,这对我来说并不困难。所有测试都通过了,但我不知道它们是否是“好的测试”。感谢您的帮助。
视图模型:
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)
}
}
测试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)
}
}
}
检查测试正确性的一种简单方法是更改被测系统并查看您的测试是否标记了错误。如果他们不这样做,那么这就是您测试中的一个漏洞。例如,以下视图模型将通过您的测试:
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] = []
}
上面的代码显然缺少一些重要的功能,这意味着您的测试不完整。