I have a class that receives an AVCaptureDevice object as a parameter and I'd like to test it. I found the swizzle method to create an instance of AVCaptureDevice
extension AVCaptureDevice {
class func swizzle() {
// Exchange class methods
[
(
#selector(AVCaptureDevice.default(_:for:position:)),
#selector(AVCaptureDevice.mockDefaultDevice(position:))
),
(
#selector(AVCaptureDevice.authorizationStatus(for:)),
#selector(AVCaptureDevice.mockAuthorizationStatus)
),
(
#selector(AVCaptureDevice.requestAccess(for:completionHandler:)),
#selector(AVCaptureDevice.mockRequestAccess)
)
].forEach {
if let original = class_getClassMethod(self, $0),
let mock = class_getClassMethod(self, $1) {
method_exchangeImplementations(original, mock)
}
}
// Add NSObject.init implementation to init(mock:)
[
(
#selector(AVCaptureDevice.init(mock:)),
#selector(NSObject.init)
)
].forEach {
if let original = class_getInstanceMethod(self, $0),
let mock = class_getInstanceMethod(self, $1) {
print("Mock:::Init Exchange impl \(original) <-> \(mock)")
method_setImplementation(original, method_getImplementation(mock))
}
}
}
@objc
convenience init(mock: String) {
fatalError("Fake method that should be replaced by NSObject.init")
}
@objc
class func mockRequestAccess(completionHandler handler: @escaping (Bool) -> Void) {
handler(true)
}
@objc
class func mockAuthorizationStatus() -> AVAuthorizationStatus {
return .authorized
}
}
It worked well to create an instance of AVCaptureDevice
using AVCaptureDevice.default(_:for:position:)
, but inside my class, this instance is used to create an AVCaptureDeviceInput
object as follows:
let deviceInput = try AVCaptureDeviceInput(device: deviceCamera)
and passing the mocked instance of deviceCamera
to AVCaptureDeviceInput
is resulting in the error "Error Domain=AVFoundationErrorDomain Code=-11852 "Não pode usar (null)" UserInfo={NSLocalizedFailureReason=Este app não tem autorização para usar (null)., AVErrorDeviceKey=<AVCaptureDevice: 0x600000cf49c0 [(null)][]>, NSLocalizedDescription=Não pode usar (null)}"
I tried to use the swizzle method again to create an instance of AVCaptureDeviceInput
extension AVCaptureDeviceInput {
class func swizzle() {
[
(
#selector(AVCaptureDeviceInput.init(device:)),
#selector(NSObject.init)
)
].forEach {
if let original = class_getInstanceMethod(self, $0),
let mock = class_getInstanceMethod(self, $1) {
method_setImplementation(original, method_getImplementation(mock))
}
}
}
}
(and other variations of this code) but it did not work. When I activate this code calling AVCaptureDeviceInput.swizzle()
my test freezes in AVCaptureDeviceInput(device:) throws
I found another question about AVCaptureDeviceInput in unit tests, but there is no solution either.
Does anyone have any idea about what I can do to test my class mocking AVCaptureDevice and AVCaptureDeviceInput? Any idea is welcome!