如何使用OCMock在不同的线程上正确存根方法?

时间:2013-03-12 21:16:53

标签: objective-c unit-testing ocmock

我有以下单元测试失败。我认为它是因为OCMock在多个线程中不能很好地工作,但我可能是错的。 mockTestMethodA永远不会被调用。如果我修改代码以在同一个线程上调用testMethodA(没有NSThread),则存根似乎有效。这是OCMock的已知限制还是我遗漏了什么?

示例代码:

- (void) testCallMethodUsingNSThreadFromADifferentClass
{
   mockTestClassA = [OCMockObject partialMockForObject:testClassA];

   [[[mockTestClassA expect] andCall:@selector(mockTestMethodA) onObject:self] testMethodA];

   [testClassC threadedRequestToCallMethodA];

   [self waitForCompletion:5.0];

   [mockTestClassA verify];
}
threadedRequestToCallMethodA中的{p> callMethodAFromTestClassCTestClassC定义如下:

- (void) threadedRequestToCallMethodA
{
    [NSThread detachNewThreadSelector:@selector(callMethodAFromTestClassC) toTarget:self withObject:nil];
}

- (void) callMethodAFromTestClassC
{
    [[[TestClassA alloc] init] testMethodA];
}
testMethodA中的

TestClassA定义为:

- (void) testMethodA
{
    NSLog(@"testMethodA");
}

Stub方法定义如下:

- (void) mockTestMethodA
{
   NSLog(@"mockTestMethodA");
}

最后waitForCompletion

- (BOOL) waitForCompletion:(NSTimeInterval)timeoutSecs
{
    NSDate  *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutSecs];
    do {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeoutDate];
        if([timeoutDate timeIntervalSinceNow] < 0.0)
        break;
    } while (!done);

   return done;
 }

感谢您的帮助。

感谢。

1 个答案:

答案 0 :(得分:0)

您的问题是,您没有在部分模拟的对象上调用测试方法,而是在callMethodAFromTestClassC中分配一个新方法。如果你在适当的对象上调用它,它工作正常。见下文(注意我实际上并没有创建一个单独的C类,但效果是一样的)。作为旁注,我认为积木和GCD让生活更轻松,但每个人都有自己的风格。

//
//  TestClassTest.m
//  TestApp
//
//  Created by Benjamin Flynn on 11/20/12.
//

#import <SenTestingKit/SenTestingKit.h>
#import "OCMock.h"
#import "TestClassA.h"

@interface TestClassTest : SenTestCase

@property (nonatomic, retain) TestClassA *testClassA;
@property (atomic, assign) BOOL done;
@end


@implementation TestClassTest

- (void) testCallMethodUsingNSThreadFromADifferentClass
{
    self.testClassA = [[TestClassA alloc] init];
    id mockTestClassA = [OCMockObject partialMockForObject:self.testClassA];
    [[[mockTestClassA expect] andCall:@selector(mockTestMethodA) onObject:self] testMethodA];
    [self threadedRequestToCallMethodA];
    [self waitForCompletion:5.0];    
    [mockTestClassA verify];
}

- (void)threadedRequestToCallMethodA
{
    [NSThread detachNewThreadSelector:@selector(callMethodAFromTestClassC) toTarget:self withObject:nil];
}


- (void)callMethodAFromTestClassC
{
    [self.testClassA testMethodA];
}

- (void)mockTestMethodA
{
    NSLog(@"Mock test method A");
    self.done = YES;
}

- (BOOL)waitForCompletion:(NSTimeInterval)timeoutSecs
{
    NSDate  *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutSecs];
    NSLog(@"Starting timer");
    do {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeoutDate];
        if([timeoutDate timeIntervalSinceNow] < 0.0)
            break;
    } while (!self.done);
    NSLog(@"Ending timer");

    return self.done;
}

@end