Я знаю, что это выглядит как обычный вопрос, но после прочтения 10-15 учебника и изучения того, как я могу написать тест для своего класса обслуживания. Я не могу решить перенести статические функции в протокол или т. Д. Для внедрения зависимостей
У меня есть сетевой слой, как на картинке ниже. Все мои классы функций (например, выборочные пользователи, новости, медиа и т. Д.) Вызывают класс "Service Caller" и после этого, если ответом является ошибка; вызывает класс «Ошибка службы» для обработки ошибки, а если нет, декодируйте JSON.
Моя проблема заключается в том, что я вызываю класс обслуживания как статическую функцию, такую как «ServiceCaller.performRequest», и если он получает ошибку, я также вызываю класс ошибки как статический, как «ServiceError.handle». Также он вызывает класс URLCache для получения пути URL запроса. Я не уверен, как я могу заставить их вводить зависимости и имитировать в тестовом классе. Как я нахожу в уроках, я должен написать это как;
protocol MyProtocol{
func myfunction() -> Void
}
class A{
let testProtocol = MyProtocol!
init(pro: MyProtocol){
testProtocol = pro
}
}
и в функции настройки в тестовом классе это возможно;
myMockProtocol = ...
myTestclass = A.init(pro: myMockProtocol)
но я не могу найти, как я могу получить статические вызовы, такие как ServiceCaller.performRequest или ServiceError.handle ..; (Упрощенная версия в нижней части вопроса)
class AppInitService{
static func initAppRequest(_ completion: @escaping (_ appInitRecevingModel: Result<AppInitRecevingModel>) -> Void) {
let sendingModel = AppInitSendingModel(cmsVersion: AppDefaults.instance.getCMSVersion())
let route = ServiceRouter(method: .post, path: URLCache.instance.getServiceURL(key: URLKeys.initApp), parameters: (sendingModel.getJSONData()), timeoutSec: 1)
ServiceCaller.performRequest(route: route) { (result) in
if let error = result.error{
if let statusCode = result.response?.statusCode{
completion(.error(ServiceError.handle(error: error, statusCode: statusCode)))
}else{
completion(.error(ServiceError.handle(error: error, statusCode: error._code)))
}
}else{
if let data = result.data{
do{
var responseJson = JSON(data)
responseJson["idleTimeoutInMinutes"] = 10
let input = try AppInitRecevingModel(data: responseJson.rawData())
completion(.success(input))
}catch let error{
completion(.error(ServiceError.handle(error: error, statusCode: -1002)))
}
}
}}
}
}
Мой тестовый класс:
class MyProjectAppInitTests: XCTestCase {
var appInitTest: AppInitService!
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
appInitTest = AppInitService.init()
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
appInitTest = nil
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
let testParamater = ["string":"test"]
let route = ServiceRouter(method: .post, path: "/testPath", parameters: testParamater.getJSONData(), timeoutSec: 10)
appInitTest. //cant call anything in here
}
Уроки, которые я искал для модульного теста;
https://www.raywenderlich.com/150073/ios-unit-testing-and-ui-testing-tutorial
https://www.swiftbysundell.com/posts/time-traveling-in-swift-unit-tests
https://marcosantadev.com/test-doubles-swift
http://merowing.info/2017/04/using-protocol-compositon-for-dependency-injection/
РЕДАКТИРОВАТЬ: одним из решений может быть написание класса инициализации для всего сетевого уровня и классов обслуживания, а затем избавиться от статических функций? Но я не уверен, что это будет хороший подход.
РЕДАКТИРОВАТЬ 2: упрощенный код;
class A{
static func b(completion:...){
let paramater = ObjectModel(somevariable: SomeClass.Singleton.getVariable()) //Data that I sent on network request
let router = ServiceRouter(somevariable: SomeClassAgain.Singleton.getsomething()) //Router class which gets parameters, http method etc..
NetworkClass.performNetworkRequest(sender: object2){ (result) in
//Result - What I want to test (Write UnitTest about)
}
}
}