使用Cedar测试presentViewController的存在

时间:2014-10-14 16:32:36

标签: uitableview cedar-bdd

当我自动点击表格行单元格时,我正在尝试测试是否存在呈现的视图控制器。当我尝试测试控制器的presentViewController是否属于给定类型的类时,它总是导致nil。我假设新呈现的视图控制器正在转换到正在呈现的视图控制器,这就是[controller presentViewController]为零的原因。

我正在使用Cedar BDD测试框架。我已经安装了PivotalCore库来提供自动“点击”功能。

这是规范代码:

#import <Cedar-iOS/Cedar-iOS.h>
#import "UITableViewCell+Spec.h"

#import "FMNavigatorViewController.h"

using namespace Cedar::Matchers;
using namespace Cedar::Doubles;

SPEC_BEGIN(FMNavigatorViewControllerSpec)

describe(@"FMNavigatorViewController", ^{
    __block UINavigationController *nav;
    __block FMNavigatorViewController *controller;

    beforeEach(^{
        FSHandle *documents = [FSHandle handleAtUrl:[[BasicFileManager sharedManager] documentsUrl] isDirectory:YES];
        // @todo Remove all files from Recent Files and Local Files.
        // Remove all configured remote connections.
        NSArray *contents = [[BasicFileManager sharedManager] contentsOfDirectoryAtURL:documents.url];
        for (NSURL *url in contents) {
            if (! [url.lastPathComponent isEqualToString:@"Local Files"] && ! [url.lastPathComponent isEqualToString:@"Recent Files"]) {
                NSLog(@"WARNING: Deleting Manager: %@", url.lastPathComponent);
                FileManager *manager = [FileManager fileManagerWithName:url.lastPathComponent];
                [manager deleteFileManager];
            }
        }
        // Create view.
        controller = [[FMNavigatorViewController alloc] initWithDirectory:documents];
        nav = [[UINavigationController alloc] initWithRootViewController:controller];
        // Initiates view lifecycle. Accessing the 'view' will automatically
        // create it.
        nav.view should_not be_nil;
        // Doesn't get called unless properly added to a heirarchy -- which I
        // haven't found the correct process for yet.
        [controller viewWillAppear:NO];
    });

    it(@"should contain Local and Recent Files with no other connections", ^{
        controller should be_instance_of([FMNavigatorViewController class]);
        // Local and Remote Connection Groups
        [controller.tableView.dataSource numberOfSectionsInTableView:controller.tableView] should equal(2);
        // Recent Files and Local Files
        [controller.tableView.dataSource tableView:controller.tableView numberOfRowsInSection:0] should equal(2);
        // Enforce order: Local Files then Recent Files.
        [[[controller.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] textLabel] text] should equal(@"Local Files");
        [[[controller.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]] textLabel] text] should equal(@"Recent Files");
        // The second group should have one row with description.
        [controller.tableView.dataSource tableView:controller.tableView numberOfRowsInSection:1] should equal(1);
        [[[controller.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]] textLabel] text] should equal(NSLocalizedString(@"CreateRemoteConnection", @""));
    });

    it(@"should display the FM wizard view", ^{
        [[controller.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]] tap];
        controller.presentedViewController should_not be_nil;
        //[nav presentedViewController] should be_instance_of([UINavigationController class]);
        //[controller presentedViewController] should be_instance_of([UINavigationController class]);
    });

});

SPEC_END

最后一次测试包含有问题的代码。我的问题是:如果presentViewController不是nil,我需要等待一两秒才能测试吗?如果是这样,我该怎么做?

以下是点击单元格后应执行的代码:

FMWizardViewController *controller = [FMWizardViewController new];
[controller setDelegate:self];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:controller];
nav.navigationBar.tintColor = UIColorFromRGB(BNAV_TINT_COLOR);
[self presentViewController:nav animated:YES completion:nil];

我仔细检查以确保在点击单元格后实际运行此代码;确实如此。

谢谢!

1 个答案:

答案 0 :(得分:0)

在Google雪松讨论组(https://groups.google.com/forum/#!forum/cedar-discuss)的帮助下,我能够弄明白。

需要做的是:

  1. 主要的运行循环需要先进行,以便实现呈现的ViewController并将其关联到相应的视图控制器
  2. 需要创建整个视图层次结构(窗口,导航控制器,FMNavigationController)
  3. #import <Cedar-iOS/Cedar-iOS.h>

    #import "UITableViewCell+Spec.h"
    
    #import "FMNavigatorViewController.h"
    
    // << -- Add this
    #define tickRunLoop (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.01, false))
    
    using namespace Cedar::Matchers;
    using namespace Cedar::Doubles;
    
    SPEC_BEGIN(FMNavigatorViewControllerSpec)
    
    describe(@"FMNavigatorViewController", ^{
        __block UIWindow *window; // <<-- and this,
        __block UINavigationController *nav;
        __block FMNavigatorViewController *controller;
    
        beforeEach(^{
            window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
            FSHandle *documents = [FSHandle handleAtUrl:[[BasicFileManager sharedManager] documentsUrl] isDirectory:YES];
            // @todo Remove all files from Recent Files and Local Files.
            // Remove all configured remote connections.
            NSArray *contents = [[BasicFileManager sharedManager] contentsOfDirectoryAtURL:documents.url];
            for (NSURL *url in contents) {
                if (! [url.lastPathComponent isEqualToString:@"Local Files"] && ! [url.lastPathComponent isEqualToString:@"Recent Files"]) {
                    NSLog(@"WARNING: Deleting Manager: %@", url.lastPathComponent);
                    FileManager *manager = [FileManager fileManagerWithName:url.lastPathComponent];
                    [manager deleteFileManager];
                }
            }
            // Create view.
            controller = [[FMNavigatorViewController alloc] initWithDirectory:documents];
            nav = [[UINavigationController alloc] initWithRootViewController:controller];
            window.rootViewController = nav;
            [window makeKeyAndVisible];
            // Initiates view lifecycle. Accessing the 'view' will automatically
            // create it.
            nav.view should_not be_nil;
            // Doesn't get called unless properly added to a heirarchy -- which I
            // haven't found the correct process for yet.
            [controller viewWillAppear:NO];
        });
    
        it(@"should contain Local and Recent Files with no other connections", ^{
            controller should be_instance_of([FMNavigatorViewController class]);
            // Local and Remote Connection Groups
            [controller.tableView.dataSource numberOfSectionsInTableView:controller.tableView] should equal(2);
            // Recent Files and Local Files
            [controller.tableView.dataSource tableView:controller.tableView numberOfRowsInSection:0] should equal(2);
            // Enforce order: Local Files then Recent Files.
            [[[controller.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] textLabel] text] should equal(@"Local Files");
            [[[controller.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]] textLabel] text] should equal(@"Recent Files");
            // The second group should have one row with description.
            [controller.tableView.dataSource tableView:controller.tableView numberOfRowsInSection:1] should equal(1);
            [[[controller.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]] textLabel] text] should equal(NSLocalizedString(@"CreateRemoteConnection", @""));
        });
    
        it(@"should display the FM wizard view", ^{
            // Sanity to ensure we are tapping the right cell.
            [[controller.tableView.visibleCells[2] textLabel] text] should equal(NSLocalizedString(@"CreateRemoteConnection", @""));
            [controller.tableView.visibleCells[2] tap];
            tickRunLoop; // <<-- and this.
            controller.presentedViewController should_not be_nil;
            controller.presentedViewController should be_instance_of([UINavigationController class]);
        });
    
    });
    
    SPEC_END
    

    现在所有测试都通过了。

    其中一位维护者表示,这个问题很可能与iOS 8中的一些内部变化有关;只要presentViewController:animated:completion:被调用,它就不会将presentViewController值关联起来。它应该在将来解决。

    我希望这有助于某人!

    更新

    我忘了补充一点,推进运行循环不是最佳做法。在问题得到解决之前,这应被视为止损。