简体   繁体   中英

How to mock storyboard view controller dependencies from tests when using Typhoon?

I'm struggling to mock a view controller dependency when using Typhoon and storyboards. When I try to patch the dependency I want to mock the patch doesn't seem to have any affect.

Please can anyone help?

Here's my Typhoon assembly:

#import "ANYApplicationAssembly.h"
#import "ANYDatabase.h"
#import "ANYTableViewController.h"

@implementation ANYApplicationAssembly

- (ANYTableViewController *)tableViewController {
    return [TyphoonDefinition withClass:[ANYTableViewController class] configuration:^(TyphoonDefinition *definition) {
        [definition injectProperty:@selector(database) with:[self theDatabase]];
    }];
}

- (ANYDatabase *)theDatabase {
    return [TyphoonDefinition withClass:[ANYDatabase class]];
}

@end

And, here's the test:

#import <OCMock/OCMock.h>
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "ANYTableViewController.h"
#import "ANYApplicationAssembly.h"
#import "ANYDatabase.h"

@interface ANYTableViewControllerTests : XCTestCase

@end

@implementation ANYTableViewControllerTests

ANYTableViewController* controller;
ANYDatabase* mockDatabase;

- (void)setUp {
    [super setUp];

    mockDatabase = OCMClassMock([ANYDatabase class]);

    ANYApplicationAssembly* assembly = [[ANYApplicationAssembly assembly] activate];
    TyphoonPatcher* patcher = [[TyphoonPatcher alloc] init];
    [patcher patchDefinitionWithSelector:@selector(theDatabase) withObject:^id{
        return mockDatabase;
    }];
    [assembly attachDefinitionPostProcessor:patcher];
    [assembly makeDefault];

    UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    controller = [storyboard instantiateViewControllerWithIdentifier:@"TableController"];
    [controller loadViewIfNeeded]; // force IBOutlets etc to be initialized
    XCTAssertNotNil(controller.view);
}

- (void)testShowsAllTheThings {
    // Given
    NSArray* allTheThings = @[@"all", @"the", @"things"];
    OCMStub([mockDatabase things]).andReturn(allTheThings);

    // When
    NSInteger sections = [controller numberOfSectionsInTableView:controller.tableView];
    NSInteger rows = [controller tableView:controller.tableView numberOfRowsInSection:0];

    // Then
    XCTAssertEqual(sections, 1);
    XCTAssertEqual(rows, 2);
}

@end

Is it possible to mock dependencies for view controllers loaded by storyboards when using Typhoon?

So, after a bit more investigating, I've found a solution but had to switch from using PList Integration to AppDelegate Integration implementing the initialFactory method:

AppDelegate.h:

- (id)initialFactory;

AppDelegate.m:

- (id)initialFactory {
    TyphoonComponentFactory *factory = ([[TyphoonBlockComponentFactory alloc] initWithAssembly:[ANYApplicationAssembly assembly]]);
    [factory makeDefault];
    return factory;
}

ANYTableViewControllerTests.m:

- (void)setUp {
    [super setUp];

    mockDatabase = OCMClassMock([ANYDatabase class]);

    ANYApplicationAssembly* assembly = (ANYApplicationAssembly*) [TyphoonComponentFactory defaultFactory];
    TyphoonPatcher* patcher = [[TyphoonPatcher alloc] init];
    [patcher patchDefinitionWithSelector:@selector(theDatabase) withObject:^id{
        return mockDatabase;
    }];
    [assembly attachDefinitionPostProcessor:patcher];

    UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    controller = [storyboard instantiateViewControllerWithIdentifier:@"TableController"];
    [controller loadViewIfNeeded]; // force IBOutlets etc to be initialized
    XCTAssertNotNil(controller.view);
}

I'd be interested to know if there's any way to get this to work using PList integration though / why it doesn't work using PList integration.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM