【问题标题】:How can I access local variables within a method for an XCTestCase using OCMock?如何使用 OCMock 在 XCTestCase 的方法中访问局部变量?
【发布时间】:2014-08-03 11:02:33
【问题描述】:

我有一个我想测试的方法:

- (void)openEmailFeedback
{
    MFMailComposeViewController* controller = [[MFMailComposeViewController alloc] init];
    controller.mailComposeDelegate = self;
    [controller setToRecipients:@"test@example.com"];
    [controller setSubject:@""];
    [controller setMessageBody:@"" isHTML:NO];
    [self presentViewController:controller animated:YES completion:nil];
}

我尝试用它测试它

- (void)testOpenEmailFeedback
{
    ViewController *vc = [[ViewController alloc] init];

    // Create a partial mock of UIApplication
    id mockMailComposeViewController = [OCMockObject mockForClass:[MFMailComposeViewController class]];
    [[mockMailComposeViewController expect] setMailComposeDelegate:vc];
    [[mockMailComposeViewController expect] setToRecipients:@[@"test@example.com"]];
    [[mockMailComposeViewController expect] setSubject:@""];
    [[mockMailComposeViewController expect] setMessageBody:@"" isHTML:NO];

    [vc openEmailFeedback];

    [mockMailComposeViewController verify];
    [mockMailComposeViewController stopMocking];
}

但我意识到 mockMailComposeViewController 与方法中的本地 MFMailComposeViewController *controller 远非同一个变量。测试时是否可以在“openEmailFeedback”方法中访问局部变量?

【问题讨论】:

    标签: ios objective-c ocmock xctest


    【解决方案1】:

    这个问题的标准答案是使用依赖注入模式。对于 OCMock 和部分模拟,您还可以使用另一种模式。只需在具有依赖项和存根的类中创建一个工厂方法。在您的视图控制器中:

    - (MFMailComposeViewController *)createComposeViewController
    {
        return [[MFMailComposeViewController alloc] init];
    }
    
    - (void)openEmailFeedback
    {
        MFMailComposeViewController* controller = [self createComposeViewController];
        controller.mailComposeDelegate = self;
        // continue as normal...
    

    在你的测试中:

    - (void)testOpenEmailFeedback
    {
    ViewController *vc = [[ViewController alloc] init];
    
    // Create a partial mock of UIApplication
    id mockMailComposeViewController = [OCMockObject mockForClass:[MFMailComposeViewController class]];
    [[mockMailComposeViewController expect] setMailComposeDelegate:vc];
    [[mockMailComposeViewController expect] setToRecipients:@[@"test@example.com"]];
    [[mockMailComposeViewController expect] setSubject:@""];
    [[mockMailComposeViewController expect] setMessageBody:@"" isHTML:NO];
    
     id vcPartialMock = [OCMockObject partialMockForObject:vc];
     [[[vcPartialMock stub] andReturn:mockMailComposeViewController] createComposeViewController];
    
     // continue as before...  
    

    【讨论】:

      【解决方案2】:

      我通常使用这种模式在我正在测试的方法中模拟本地创建的对象-

      MyClass *instance = [[MyClass alloc] init];
      id mockMyClassObj = [OCMockObject mockForClass:[MyClass class]];
      [[[mockMyClassObj stub] andReturn:instance] alloc];
      

      然后在断言中 -

      // Lets say I am testing for property 'whatever' being nil after calling the method I am testing
      XCTAssertNil(instance.whatever, @"whatever should be nil");
      

      这是该代码的 Xcode sn-p -

      <#Class#> *<#instance#> = [[<#Class#> alloc] init];
      id mock<#name#> = [OCMockObject mockForClass:[<#class#> class]];
      [[[mock<#name#> stub] andReturn:<#instance#>] alloc];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-16
        • 1970-01-01
        • 1970-01-01
        • 2014-09-14
        • 2014-07-29
        • 2020-07-30
        相关资源
        最近更新 更多