Skip to content

Instantly share code, notes, and snippets.

@GRGBISHOW
Created March 25, 2024 13:20
Show Gist options
  • Save GRGBISHOW/dcdead820b0c922d10278d0de3c35c1b to your computer and use it in GitHub Desktop.
Save GRGBISHOW/dcdead820b0c922d10278d0de3c35c1b to your computer and use it in GitHub Desktop.
Testability with protocol witness. Have you ever reached to point where protocol based mock gets complex, and doesn't provide variance and flexibility, well here is a small idea how protocol witness will solve the problem
//MARK:- ------------------------------------- Main Target ---------------------------------------------------------
struct DeviceInfo {
var isTablet: Bool { UIDevice.current.userInterfaceIdiom == .pad }
var vendorIdentifler: () -> String? = { UIDevice.current.identifierForVendor?.uuidString }
var isPhone: Bool { UIDevice.current.userInterfaceIdiom == .phone }
var systemName: () -> String = { UIDevice.current.systemName }
var systemversion: () -> String = { UIDevice.current.systemVersion }
var batteryLevel: () -> Float = {
UIDevice.current.isBatteryMonitoringEnabled = true
return UIDevice.current.batteryLevel
}
var batteryState: () -> UIDevice.BatteryState = {
UIDevice.current.isBatteryMonitoringEnabled = true
return UIDevice.current.batteryState
}
}
struct DependentSystem {
lazy var device = DeviceInfo()
// add other dependent systems
}
var DependencyStore = DependentSystem() // Single instance in whole app
// Your some viewModel
class SomeViewModel {
var shouldSendNotification = false
func someFunction() {
//Some Business logic
shouldSendNotification = DependencyStore.device.batteryState() == .full
}
}
//MARK:- ------------------------------------- Test Target ---------------------------------------------------------
// DeviceInfo mock
extension DeviceInfo {
static let mock: Self = Self(vendorIdentifler: { "1235" },
systemName: { "iPadOS"},
systemversion: { "17.2" },
batteryLevel: { 0.5 },
batteryState: { .charging }
)
}
// DependentSystem mock
extension DependentSystem {
static let mock: Self = .init(device: .mock)
}
// SomeViewModel Test
final class SomeViewModelTests: XCTestCase {
var viewModel: SomeViewModel!
override func setUp() {
super.setUp()
DependencyStore = .mock
viewModel = SomeViewModel()
}
override func tearDown() {
viewModel = nil
super.tearDown()
}
func test_someFunction() {
viewModel.someFunction()
XCTAssertFalse(viewModel.shouldSendNotification)
DependencyStore.device.batteryState = { .full }
viewModel.someFunction()
XCTAssertTrue(viewModel.shouldSendNotification)
DependencyStore.device.batteryState = { .charging }
viewModel.someFunction()
XCTAssertTrue(viewModel.shouldSendNotification)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment