如何使用OCMock访问XCTestCase的方法中的局部变量?

时间:2014-06-13 00:26:31

标签: ios objective-c ocmock xctest

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

- (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 *控制器相同的变量。是否有可能如何访问方法中的局部变量" openEmailFeedback"在测试时?

2 个答案:

答案 0 :(得分:3)

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

- (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...  

答案 1 :(得分:0)

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

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代码段 -

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