3

I have a VIPER architecture setup and am trying to unit test the instantiation of the wireframe.

For anyone who doesn't know what VIPER is, the key parts to understand are that there is are 4 classes that that have key responsibilities. The wireframe creates the other 3 (the view, presenter, and interactor). The wireframe then connects them appropriately like below:

                              Wireframe
                                  ^
                                  |
                                  v
                     View <-> Presenter <-> Interactor

So I am creating the unit tests in Swift, and am having difficulty making sure these connections are setup. Note, the code itself works, the asserts in the unit tests are the problem.

func testInitWithNothingShouldInstantiateVIPERStackAndConnectLayers() {
    wireframe = LoginWireframe()       

    XCTAssertEqual(wireframe.modulePresenter, wireframe.moduleInteractor.presenter, "Interactor's presenter must be the module's presenter")

    XCTAssert(wireframe.modulePresenter === wireframe.moduleInteractor.presenter, "Interactor's presenter must be the module's presenter")
}

Neither of these two asserts compiles correctly.

For the XCTAssertEqual this error occurs

Cannot find an overload for 'XCTAssertEqual' that accepts an argument list of type '(LoginPresenter, LoginInteractorOutput, String)'

For the XCTAssert (or XCTAssertTrue), this error occurs

Cannot invoke 'XCTAssert' with an argument list of type '(Bool, String)'

For completeness and because someone may find the code useful:

//LoginWireframe.swift
class LoginWireframe: NSObject, LoginWireframeInterface {
    lazy var moduleInteractor = LoginInteractor()
    lazy var modulePresenter = LoginPresenter()
    lazy var moduleView = LoginView()
    lazy var presenter : LoginRouting = self.modulePresenter

    override init() {
            super.init()

            let i = moduleInteractor
            let p = modulePresenter
            let v = moduleView

            i.presenter = p

            p.interactor = i
            p.view = v
            p.wireframe = self

            v.presenter = p

            presenter = p
}

//LoginInteractor.swift
class LoginInteractor: NSObject, LoginInteractorInput {
    lazy var presenter : LoginInteractorOutput = LoginPresenter()
}

//LoginPresenter.swift
class LoginPresenter : NSObject, LoginInteractorOutput, LoginPresenterInterface, LoginRouting {
    lazy var interactor : LoginInteractorInput = LoginInteractor()
    lazy var view : LoginViewInterface = LoginView()
    lazy var wireframe : LoginWireframeInterface = LoginWireframe()
}

//LoginView.swift
class LoginView : UIViewController, LoginViewInterface {
    lazy var presenter : LoginPresenterInterface = LoginPresenter()
 }
Kevin
  • 16,696
  • 7
  • 51
  • 68
ColdLogic
  • 7,206
  • 1
  • 28
  • 46

2 Answers2

2

I hate being the guy that answers his own questions, but:

I had to make every protocol be considered a class, then use nil coalescence on the result reference operator to get this to work out.

protocol LoginInteractorInput : class {

}

func testInitWithNothingShouldInstantiateVIPERStackAndConnectLayers() {
    wireframe = LoginWireframe()       

    XCTAssert(wireframe.modulePresenter === wireframe.moduleInteractor.presenter ? true : false, "Interactor's presenter must be the module's presenter")
}

This makes sure that the modules presenter points to the same object as the modules interactor's presenter.

ColdLogic
  • 7,206
  • 1
  • 28
  • 46
0

as far as compiler knows you are trying to compare LoginPresenter (concrete class inheriting equality from NSObject) with LoginInteractorOutput – an interface that, it seems (sources would help), does not extend Equatable. So it does not know how to compare those two.

Possible solutions:

  • force cast LoginPresenter (not nice)
  • Make you LoginInteractorOutput inherit Equatable by implementing func ==(las: LoginInteractorOutput, hrs: LoginInteractorOutput) -> Bool
Sash Zats
  • 5,376
  • 2
  • 28
  • 42