Search code examples
swifttyphoon

Different Assembly for Tests


I use Swift, CocoaPods and Typhoon for my project. I have some classes which provide me Webservice stuff. In my tests i want to use a different class which actually don't call the Webservice. So I thought it would be a good idea to just use another assembly for the test where i inject the fake webservice class.

@objc public protocol AuthService {
    func auth(username: String!, password:String!, onSuccess: (Token!) -> (Void), onError:(NSError!) -> (Void))
}

// "real" implementation
public class AuthServiceImpl: NSObject, AuthService {
    public func auth(username: String!, password:String!, onSuccess: (Token!) -> (Void), onError:(NSError!) -> (Void)){
       // do some webservice calls
    }
}

 // "fake" implementation
public class AuthServiceTestImpl: NSObject, AuthService {
    public func auth(username: String!, password:String!, onSuccess: (Token!) -> (Void), onError:(NSError!) -> (Void)){
       // do some file readings
    }
}

Pods File

platform :ios, '8.0'

target :Project, :exclusive => true do
   pod 'Typhoon', '~> 2.3.4'
end

The problem is that i get "Use of undeclared type 'TyphoonAssembly'" in my Assembly for the tests. Is there are Best Practice how to inject something else in test with typhoon?


Solution

  • This is called Modularizing Assemblies and is outlined in the user guide here.

    The key concepts are:

    • You define recipes to build instances in an assembly. Some of these instance may refer to objects defined in another assembly. For example our view controller that depends on a service client.
    • To refer to objects that will come from another assembly simply create a property of the type of that assembly. Eg TyphoonAssembly<MyProtocol> or MyAssemblyType*.
    • Typhoon always proxies references to collaborating assemblies. The concrete realization is provided at startup time. You can provide an alternative implementation of the protocol or a sub-class.

    To bootstrap Typhoon for tests:

    let applicationAssembly = ApplicationAssembly()
    let networkComponents = TestNetworkComponents()
    TyphoonAssemblyActivator.withAssemblies([
        applicationAssembly, 
        networkComponents]).activate()
    
    //This view controller will now be injected with test network components. 
    let controller = assembly.viewController() as MyViewController
    

    Good practice: If you wish to reuse the above assembly in several different test classes, create a method for that to avoid duplication.

    Alternatively you may wish to patch a single component, which is outlined in the integration testing guide.