Skip to content

Instantly share code, notes, and snippets.

@agiokas
Last active January 2, 2022 20:59
Show Gist options
  • Save agiokas/35b681c0b02e2e9eeb5d034477792213 to your computer and use it in GitHub Desktop.
Save agiokas/35b681c0b02e2e9eeb5d034477792213 to your computer and use it in GitHub Desktop.
ViewModel test example
import Foundation
final class Datasource {
func pets() -> [Pet] {
[
Pet(id: "1", name: "Max", ownerId: "1"),
Pet(id: "2", name: "Azor", ownerId: "1"),
Pet(id: "3", name: "Monty", ownerId: "2"),
Pet(id: "4", name: "Zizou", ownerId: "3"),
]
}
func persons() -> [Person] {
[
Person(id: "1", firstName: "Apo", lastName: ""),
Person(id: "3", firstName: "Melanie", lastName: ""),
Person(id: "4", firstName: "Mustermann", lastName: ""),
]
}
}
import Foundation
protocol DatasourceInterface {
func pets() -> [Pet]
func persons() -> [Person]
}
final class Datasource: DatasourceInterface {
func pets() -> [Pet] {
[
Pet(id: "1", name: "Max", ownerId: "1"),
Pet(id: "2", name: "Azor", ownerId: "1"),
Pet(id: "3", name: "Monty", ownerId: "2"),
Pet(id: "4", name: "Zizou", ownerId: "3"),
]
}
func persons() -> [Person] {
[
Person(id: "1", firstName: "Apo", lastName: ""),
Person(id: "3", firstName: "Melanie", lastName: ""),
Person(id: "4", firstName: "Mustermann", lastName: ""),
]
}
}
import Foundation
struct Person: Identifiable {
let id: String
let firstName: String
let lastName: String
}
struct Pet: Identifiable {
let id: String
let name: String
let ownerId: String
}
final class MyViewModel {
private let persons: [Person]
private let pets: [Pet]
init(persons: [Person], pets: [Pet]) {
self.persons = persons
self.pets = pets
}
func listData() -> [MyViewModel.Data] {
pets.compactMap { pet in
guard let owner = persons.first(where: { $0.id == pet.ownerId }) else {
return nil
}
return MyViewModel.Data(petName: pet.name,
owner: owner.firstName)
}
}
struct Data: Equatable {
let petName: String
let owner: String
}
}
import Foundation
final class MyViewModel2 {
private let datasource = Datasource()
func listData() -> [MyViewModel.Data] {
datasource
.pets()
.compactMap { pet in
guard let owner = datasource
.persons()
.first(where: { $0.id == pet.ownerId }) else {
return nil
}
return Data(petName: pet.name, owner: owner.firstName)
}
}
}
final class MyViewModel2 {
private let datasource: DatasourceInterface
init(datasource: DatasourceInterface) {
self.datasource = datasource
}
func listData() -> [MyViewModel.Data] {
datasource
.pets()
.compactMap { pet in
guard let owner = datasource
.persons()
.first(where: { $0.id == pet.ownerId }) else {
return nil
}
return MyViewModel.Data(petName: pet.name, owner: owner.firstName)
}
}
}
import XCTest
@testable import UnitTesting101
final class MyViewModel2Tests: XCTestCase {
func testListData() {
let viewModel = MyViewModel2(datasource: DatasourceMock())
let expectedData: [MyViewModel.Data] = [
.init(petName: "Max", owner: "Apo"),
.init(petName: "Azor", owner: "Apo"),
.init(petName: "Zizou", owner: "Melanie"),
]
XCTAssertEqual(viewModel.listData(), expectedData)
}
}
struct DatasourceMock: DatasourceInterface {
func pets() -> [Pet] {
samplePets()
}
func persons() -> [Person] {
samplePersons()
}
}
private func samplePets() -> [Pet] {
[
Pet(id: "1", name: "Max", ownerId: "1"),
Pet(id: "2", name: "Azor", ownerId: "1"),
Pet(id: "3", name: "Monty", ownerId: "2"),
Pet(id: "4", name: "Zizou", ownerId: "3"),
]
}
private func samplePersons() -> [Person] {
[
Person(id: "1", firstName: "Apo", lastName: ""),
Person(id: "3", firstName: "Melanie", lastName: ""),
Person(id: "4", firstName: "Mustermann", lastName: ""),
]
}
import Foundation
final class MyViewModel3 {
private let datasource: UserDefaults
init(datasource: UserDefaults) {
self.datasource = datasource
}
func listData() -> [MyViewModel.Data] {
pets()
.compactMap { pet in
guard let owner = persons()
.first(where: { $0.id == pet.ownerId }) else {
return nil
}
return MyViewModel.Data(petName: pet.name, owner: owner.firstName)
}
}
private func pets() -> [Pet] {
guard let data = datasource.data(forKey: "Pets"),
let petsData = try? PropertyListDecoder().decode([Pet].self, from: data) else {
return []
}
return petsData
}
private func persons() -> [Person] {
guard let data = datasource.data(forKey: "Persons"),
let personsData = try? PropertyListDecoder().decode([Person].self, from: data) else {
return []
}
return personsData
}
}
import XCTest
@testable import UnitTesting101
final class MyViewModel3Tests: XCTestCase {
func testListData() throws {
guard let userDefaults = UserDefaults(suiteName: "MyViewModel3Tests") else {
XCTFail("User defaults needed")
return
}
let encodedPets = try PropertyListEncoder().encode(samplePets())
let encodedPersons = try PropertyListEncoder().encode(samplePersons())
userDefaults.set(encodedPets, forKey: "Pets")
userDefaults.set(encodedPersons, forKey: "Persons")
userDefaults.synchronize()
let viewModel = MyViewModel3(datasource: userDefaults)
let expectedData: [MyViewModel.Data] = [
.init(petName: "Max", owner: "Apo"),
.init(petName: "Azor", owner: "Apo"),
.init(petName: "Zizou", owner: "Melanie"),
]
XCTAssertEqual(viewModel.listData(), expectedData)
}
}
private func samplePets() -> [Pet] {
[
Pet(id: "1", name: "Max", ownerId: "1"),
Pet(id: "2", name: "Azor", ownerId: "1"),
Pet(id: "3", name: "Monty", ownerId: "2"),
Pet(id: "4", name: "Zizou", ownerId: "3"),
]
}
private func samplePersons() -> [Person] {
[
Person(id: "1", firstName: "Apo", lastName: ""),
Person(id: "3", firstName: "Melanie", lastName: ""),
Person(id: "4", firstName: "Mustermann", lastName: ""),
]
}
final class MyViewModel3_v2Tests: XCTestCase {
func testListData() throws {
let userDefaults = UserDataStoreInterfaceMock()
let encodedPets = try PropertyListEncoder().encode(samplePets())
let encodedPersons = try PropertyListEncoder().encode(samplePersons())
userDefaults.dataStub = { key in
if key == "Persons" {
return encodedPersons
}
if key == "Pets" {
return encodedPets
}
return nil
}
let viewModel = MyViewModel3(datasource: userDefaults)
let expectedData: [MyViewModel.Data] = [
.init(petName: "Max", owner: "Apo"),
.init(petName: "Azor", owner: "Apo"),
.init(petName: "Zizou", owner: "Melanie"),
]
XCTAssertEqual(viewModel.listData(), expectedData)
}
}
final class UserDataStoreInterfaceMock: UserDataStoreInterface {
var dataStub: (String) -> Data? = { _ in nil }
func data(forKey defaultName: String) -> Data? {
dataStub(defaultName)
}
}
import XCTest
@testable import UnitTesting101
final class MyViewModelTests: XCTestCase {
func testListData() {
let viewModel = MyViewModel(persons: samplePersons(), pets: samplePets())
let expectedData: [MyViewModel.Data] = [
.init(petName: "Max", owner: "Apo"),
.init(petName: "Azor", owner: "Apo"),
.init(petName: "Zizou", owner: "Melanie"),
]
XCTAssertEqual(viewModel.listData(), expectedData)
}
private func samplePets() -> [Pet] {
[
Pet(id: "1", name: "Max", ownerId: "1"),
Pet(id: "2", name: "Azor", ownerId: "1"),
Pet(id: "3", name: "Monty", ownerId: "2"),
Pet(id: "4", name: "Zizou", ownerId: "3")
]
}
private func samplePersons() -> [Person] {
[
Person(id: "1", firstName: "Apo", lastName: ""),
Person(id: "3", firstName: "Melanie", lastName: ""),
Person(id: "4", firstName: "Mustermann", lastName: ""),
]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment