Skip to content

Commit

Permalink
Mock viper components and test router functions (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
ferranabello committed Mar 21, 2017
1 parent 820b985 commit 877f9f5
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Viperit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
53388C291DD9FFDF00EA4CEC /* Viperit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5367C0CF1DD7C68D005B6676 /* Viperit.framework */; };
53388C2A1DD9FFDF00EA4CEC /* Viperit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5367C0CF1DD7C68D005B6676 /* Viperit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5360ADF31E81280100C1AACB /* PresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5360ADF21E81280100C1AACB /* PresenterTests.swift */; };
5367C0DC1DD7C69E005B6676 /* ViperitError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53532C641DD50DDF00088AAC /* ViperitError.swift */; };
5367C0DD1DD7C69E005B6676 /* ViperComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53532C631DD50DDF00088AAC /* ViperComponent.swift */; };
5367C0DE1DD7C69E005B6676 /* Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53532C5F1DD50DDF00088AAC /* Module.swift */; };
Expand Down Expand Up @@ -91,6 +92,7 @@
53532C621DD50DDF00088AAC /* UserInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserInterface.swift; sourceTree = "<group>"; };
53532C631DD50DDF00088AAC /* ViperComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViperComponent.swift; sourceTree = "<group>"; };
53532C641DD50DDF00088AAC /* ViperitError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViperitError.swift; sourceTree = "<group>"; };
5360ADF21E81280100C1AACB /* PresenterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresenterTests.swift; sourceTree = "<group>"; };
5367C0CF1DD7C68D005B6676 /* Viperit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Viperit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5368EDC61E7FF91F0028D8CA /* RouterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouterTests.swift; sourceTree = "<group>"; };
5368EDC81E7FF9A40028D8CA /* TestModules.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestModules.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -212,6 +214,7 @@
children = (
534AF1EF1E7BED06009D2D61 /* Sample */,
537D19E31E7BE9B100A758FF /* ModuleTests.swift */,
5360ADF21E81280100C1AACB /* PresenterTests.swift */,
5368EDC61E7FF91F0028D8CA /* RouterTests.swift */,
53532C521DD50BD200088AAC /* Info.plist */,
);
Expand Down Expand Up @@ -500,6 +503,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5360ADF31E81280100C1AACB /* PresenterTests.swift in Sources */,
5368EDD61E801EDB0028D8CA /* SampleView.swift in Sources */,
5368EDD21E801EDB0028D8CA /* SampleDisplayData.swift in Sources */,
5368EDC91E7FF9A40028D8CA /* TestModules.swift in Sources */,
Expand Down
24 changes: 23 additions & 1 deletion Viperit/Core/Module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public struct Module {
}
}

//MARK: - Inject Mock View for Testing
//MARK: - Inject Mock Components for Testing
public extension Module {

public mutating func injectMock(view mockView: UserInterface) {
Expand All @@ -57,6 +57,28 @@ public extension Module {
view._displayData = displayData
presenter._view = view
}

public mutating func injectMock(interactor mockInteractor: Interactor) {
interactor = mockInteractor
interactor._presenter = presenter
presenter._interactor = interactor
}

public mutating func injectMock(presenter mockPresenter: Presenter) {
presenter = mockPresenter
presenter._view = view
presenter._interactor = interactor
presenter._router = router
view._presenter = presenter
interactor._presenter = presenter
router._presenter = presenter
}

public mutating func injectMock(router mockRouter: Router) {
router = mockRouter
router._presenter = presenter
presenter._router = router
}
}


Expand Down
4 changes: 3 additions & 1 deletion Viperit/Core/Router.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ open class Router {
}

open func show(from: UIViewController, setupData: Any, embedInNavController: Bool = false) {
print(ViperitError.methodNotImplemented.description)
let view = embedInNavController ? embedInNavigationController() : _view
_presenter.setupView(data: setupData)
from.show(view, sender: nil)
}

required public init() { }
Expand Down
118 changes: 118 additions & 0 deletions ViperitTests/PresenterTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//
// PresenterTests.swift
// Viperit
//
// Created by Ferran Abelló on 21/03/2017.
// Copyright © 2017 Ferran Abelló. All rights reserved.
//

import XCTest
import Viperit

//MARK: - Timeout
private let kTimeout: TimeInterval = 0.5

//MARK: - View Lifecycle
private let kViewHasLoaded = "viewHasLoaded"
private let kViewIsAboutToAppear = "viewIsAboutToAppear"
private let kViewHasAppeared = "viewHasAppeared"
private let kViewIsAboutToDisappear = "viewIsAboutToDisappear"
private let kViewHasDisappeared = "viewHasDisappeared"

//MARK: - Setup methods
private let kSetupView = "setupView"

//MARK: - Mock Presenter
private class MockPresenter: Presenter, SamplePresenterInterface {
var expectation: XCTestExpectation!
var methodExpected: String!

private func assert(method: String) {
if methodExpected == method {
XCTAssert(true)
expectation.fulfill()
}
}

override func viewHasLoaded() {
assert(method: kViewHasLoaded)
}

override func viewIsAboutToAppear() {
assert(method: kViewIsAboutToAppear)
}

override func viewHasAppeared() {
assert(method: kViewHasAppeared)
}

override func viewIsAboutToDisappear() {
assert(method: kViewIsAboutToDisappear)
}

override func viewHasDisappeared() {
assert(method: kViewHasDisappeared)
}

override func setupView(data: Any) {
assert(method: kSetupView)
}
}

//MARK: - Presenter Tests
class PresenterTests: XCTestCase {
private func createTestModuleWithMockPresenter(methodToTest: String) -> Module {
var module = Module.build(TestModules.sample, bundle: Bundle(for: SampleRouter.self))
let mockPresenter = MockPresenter()
mockPresenter.expectation = expectation(description: "Expecting method: \(methodToTest)")
mockPresenter.methodExpected = methodToTest
module.injectMock(presenter: mockPresenter)
return module
}

private func expectViewLifecycle(method: String) {
let module = createTestModuleWithMockPresenter(methodToTest: method)

//Simulate view lifecycle
_ = module.view.view
module.view.viewWillAppear(false)
module.view.viewDidAppear(false)
module.view.viewWillDisappear(false)
module.view.viewDidDisappear(false)

expect(timeout: kTimeout, errorMessage: "\(method) timed out (> \(kTimeout)s")
}


func testViewHasLoaded() {
expectViewLifecycle(method: kViewHasLoaded)
}

func testViewIsAboutToAppear() {
expectViewLifecycle(method: kViewIsAboutToAppear)
}

func testViewHasAppeared() {
expectViewLifecycle(method: kViewHasAppeared)
}

func testSetupView() {
let mockView = UIViewController()
_ = mockView.view
let module = createTestModuleWithMockPresenter(methodToTest: kSetupView)

//Simulate show module with router function using setup data
module.router.show(from: mockView, setupData: "randomData")
expect(timeout: kTimeout, errorMessage: "\(kSetupView) timed out (> \(kTimeout)s")
}


func expect(timeout: TimeInterval, errorMessage: String) {
waitForExpectations(timeout: timeout) { error in
guard error != nil else { return }
XCTFail(errorMessage)
}
}


}
8 changes: 8 additions & 0 deletions ViperitTests/Sample/SamplePresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,17 @@
import Foundation
import Viperit

//Public API for Presenter (these methods will be visible from the View)
protocol SamplePresenterInterface {
}

final class SamplePresenter: Presenter {
}

extension SamplePresenter: SamplePresenterInterface {

}


// MARK: - VIPER COMPONENTS API (Auto-generated code)
private extension SamplePresenter {
Expand Down
4 changes: 2 additions & 2 deletions ViperitTests/Sample/SampleView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ extension SampleView: SampleViewInterface {

// MARK: - VIPER COMPONENTS API (Auto-generated code)
private extension SampleView {
var presenter: SamplePresenter {
return _presenter as! SamplePresenter
var presenter: SamplePresenterInterface {
return _presenter as! SamplePresenterInterface
}
var displayData: SampleDisplayData {
return _displayData as! SampleDisplayData
Expand Down

0 comments on commit 877f9f5

Please sign in to comment.