Ad
How To Writ Good Test For My ViewModel? (RxSwift)
I wrote some tests for my ViewModel. I use RxSwift in this project. 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. 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 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)
}
}
}
Ad
Answer
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:
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.
Ad
source: stackoverflow.com
Related Questions
- → Function Undefined in Axios promise
- → What are the pluses/minuses of different ways to configure GPIOs on the Beaglebone Black?
- → Click to navigate on mobile devices
- → Playing Video - Server is not correctly configured - 12939
- → How to allow api access to android or ios app only(laravel)?
- → Axios array map callback
- → Access the Camera and CameraRoll on Android using React Native?
- → Update React [Native] View on Day Change
- → Shopify iOS SDK - issue converting BuyProductVariant to BuyProduct
- → BigCommerce and shopify API
- → Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `ListView`
- → React Native - Differences between Android and IOS
- → What is the difference between React Native and React?
Ad