Search code examples
iosunit-testingtyphoon

Injecting mock with Typhoon


I'm trying to write XCTest and inject mocked dependency with Typhoon.

Here is code in my ViewController:

   - (instancetype)init {
    self = [super init];

    MDMainAssembly *assembly = (MDMainAssembly *) [TyphoonComponentFactory defaultFactory];
    self.alertManager = [assembly alertManager];

    return self;
   }

Here is how I'm trying to change injection:

    self.mockedAlertManager = mock([MDAlertManager class]);

    MDMainAssembly *assembly = [MDMainAssembly assembly];
    TyphoonComponentFactory *factory = [TyphoonBlockComponentFactory factoryWithAssembly:assembly];
    TyphoonPatcher *patcher = [[TyphoonPatcher alloc] init];
    [patcher patchDefinition:[assembly alertManager] withObject:^id {
        return self.mockedAlertManager;
    }];

    [factory attachPostProcessor:patcher];

However tests are failing because this factory not possible to set as default. I configure in AppDelegate factory:

    TyphoonComponentFactory *factory = [[TyphoonBlockComponentFactory alloc] initWithAssemblies:@[
        [MDMainAssembly assembly],
    ]];
    [factory makeDefault];

How to get out of this situation?


Solution

  • We created the defaultFactory feature for a limited number of cases. The main is:

    • Getting access to Typhoon and looking up a dependency for a class that isn't being managed by Typhoon. Generally this isn't required.

    Although you could use it in tests, we recommend instead creating and destroying a Typhoon container for each test run. To avoid duplication, you could create a method as follows:

    @implementation IntegrationTestUtils
    
    + (TyphoonComponentFactory*)testAssembly
    {
        TyphoonComponentFactory* factory = [[TyphoonBlockComponentFactory alloc] initWithAssemblies:@[
            [MyAppAssembly assembly],
            [MyAppKernel assembly],
            [MyAppNetworkComponents assembly],
            [MyAppPersistenceComponents assembly]
        ]];
    
        id <TyphoonResource> configurationProperties = [TyphoonBundleResource withName:@"Configuration.properties"];
        [factory attachPostProcessor:[TyphoonPropertyPlaceholderConfigurer configurerWithResource:configurationProperties]];
    
        return factory;
    }
    

    . . if required you could attach a patcher to this assembly.

    Attaching a patcher to the default factory:

    If you were to apply a patcher to the default assembly, you'd most probably want to un-patch again. This feature is in the backlog here.