Probar un presentador usando PromiseKit

El patrón MVP en el desarrollo de aplicaciones móviles es una forma bastante simple de descargar ViewController y colocar parte de la lógica en el presentador. El presentador comienza a adquirir una lógica fácil de probar.


Que haya una pantalla MelodyListViewController muestre una lista de melodías. Tiene un presentador MelodyListPresenter que le dice a ViewController qué mostrar. El presentador tomará datos del servicio MelodyService . MelodyService es un contenedor sobre la base de datos y el cliente de API que descarga melodías. Si la red está disponible, el servicio toma datos de la API, de lo contrario, de la base de datos. Los tipos de errores de carga se presentan en enum ServiceRequestError .


 protocol MelodyListViewController: class { func showMelodies(melodies: [Melody]) func showLoadError(error: ServiceRequestError) } protocol MelodyListPresenter { var view: MelodyListViewController? { get } var melodyService: MelodyService { get } func fetchMelodies() -> Promise<Void> } extension MelodyListPresenter { func fetchMelodies() -> Promise<Void> { return melodyService.getMelodies().done { melodies in self.view?.showMelodies(melodies: melodies) }.catch { error in self.view?.showLoadError(error: error) } } } protocol MelodyService { func getMelodies() -> Promise<[Melody]> } public enum ServiceRequestError: Error { case unknownError case noNetwork case noData } 

Habiendo construido tal estructura de pantalla, puede hacer la prueba. A saber, probar la recepción de datos por parte del presentador. El presentador tiene una dependencia MelodyService , por lo que debe burlarse de este protocolo. Acordemos que Melody tiene un método de mocks estático que devuelve una lista de melodías arbitrarias.


 class MelodyServiceMock: MelodyService, ServiceRequestMock { var emulatedResult: ServiceRequestResult = .error(.unknownError) func getMelodies() -> Promise<[Melody]> { let melodies = Melody.mocks() return mock(result: emulatedResult, model: melodies) } } enum ServiceRequestResult { case success case error(ServiceRequestError) } 

También mojamos ViewController.


 class MelodyListViewControllerMock: MelodyListViewController { var shownMelodies: [Melody]? var shownError: ServiceRequestError? func showMelodies(melodies: [Melody]) { shownMelodies = melodies } func showLoadError(error: ServiceRequestError) { shownError = error } } 

ServiceRequestMock es un protocolo que tiene un solo método func mock<T>(result: ServiceRequestResult, model: T) -> Promise<T> , que devuelve Promise. En esta Promesa, se protegen las melodías o un error de arranque, lo que se transmite como un resultado simulado.


 protocol ServiceRequestMock { func mock<T>(result: ServiceRequestResult, model: T) -> Promise<T> } extension ServiceRequestMock { func mock<T>(result: ServiceRequestResult, model: T) -> Promise<T> { return Promise { seal in switch result { case .success: return seal.fulfill(model) case .error(let requestError): return seal.reject(requestError) } } } } 

Por lo tanto, proporcionamos todo lo necesario para probar el presentador.


 import XCTest import PromiseKit class MelodyListPresenterTests: XCTestCase { let view = MelodyListViewControllerMock() let melodyService = MelodyServiceMock() var presenter: MelodyListPresenterImp! override func setUp() { super.setUp() presenter = MelodyListPresenterImp( melodyService: melodyService, view: view) view.presenter = presenter } func test_getMelodies_success() { // given let melodiesMock = Melody.mocks() melodyService.emulatedResult = .success // when let fetchMelodies = presenter.fetchMelodies() // then fetchMelodies.done { melodies in XCTAssertNotNil(self.view.shownMelodies) XCTAssert(self.view.shownMelodies == melodiesMock) }.catch { _ in XCTFail("Failed melodies upload") } } func test_getMelodies_fail() { // given melodyService.emulatedResult = .error(.noNetwork) // when let fetchMelodies = presenter.fetchMelodies() // then fetchMelodies.done { melodies in XCTFail("Mistakenly uploaded melodies") }.catch { _ in XCTAssertNotNil(self.view.shownError) XCTAssert(self.view.shownError is ServiceRequestError) XCTAssert(self.view.shownError as! ServiceRequestError == .noNetwork) } } } 

Como resultado, obtuvimos una herramienta conveniente para escribir pruebas.

Source: https://habr.com/ru/post/es425069/


All Articles