ios - 如何对依赖于 Objective-C 中的 volatile 变量的方法进行单元测试?

标签 ios objective-c multithreading unit-testing

这是我的类(class)的简化版本:

@interface RTMovieBuilder : NSObject
@property (atomic, getter = isCancelled) volatile BOOL cancelled;
@property (nonatomic, weak) id<BuilderDelegate>delegate;
- (void)moviesFromJSON:(id)JSON;
- (Movie *)movieFromDictionary:(NSDictionary *)dict;
- (void)cancel;
@end

@implementation RTMovieBuilder

- (void)moviesFromJSON:(id)JSON
{
    // Check for errors -> If good, then do...

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        [self syncrouslyCreateMoviesFromJSON:JSON];
        });
}

- (void)syncrouslyCreateMoviesFromJSON:(id)JSON
{        
    NSMutableArray *movies = [NSMutableArray array];

    for (NSDictionary *dict in JSON)
    {
        if ([self isCancelled])
            return;
        else
            [movies addObject:[self movieFromDictionary:dict]];
    }

    [self notifyDelegateCreatedObjects:movies];
}

- (Movie *)movieFromDictionary:(NSDictionary *)dict
{
    Movie *movie = [[Movie alloc] init];
    // Set movie properties based on dictionary...
    return movie;
}

- (void)cancel
{
    [self setCancelled:YES];
}

// ... Other methods omitted for brevity's sake

@end

属性cancelledatomicvolatile 因为它可以被其他线程访问(即主线程可以调用cancel 方法来停止操作)。 (我相信这些是必需的,如果不需要,请注意为什么它不在您的答案中。)

我正在尝试编写单元测试以确保它在编写 View Controller 类之前能够正常工作。

RTMovieBuilder 正在创建 movies 时,我如何编写一个单元测试来模拟对 cancel 的调用?

编辑

这是我已经编写的单元测试,这些测试可确保 notifyDelegateCreatedObjects: 在首先调用 cancel 时不会被调用。

- (void)testIfCancelledDoesntNotifyDelegateOfSuccess
{
    // given
    RTMovieBuilder *builder = [[RTMovieBuilder alloc] init];
    builder.delegate = mockProtocol(@protocol(BuilderDelegate));

    // when
    [builder cancel];
    [builder notifyDelegateCreatedObjects:@[]];

    // then
    [verifyCount(builder.delegate, never()) builder:builder createdObjects:anything()];
}

我正在使用 OCHamcrestOCMockito。该测试通过。

最佳答案

我会避免尝试在单元测试中模拟线程时序,而是更专注于找出所有可能的最终状态,而不管时序落在何处,并在这些条件下编写代码测试。正如 bbum 也指出的那样,这可以避免测试中无穷无尽的复杂性。

在您的情况下,您需要测试的条件似乎是对 notifyDelegateCreatedObjects 的调用是否发生在操作取消之后,因为取消来得太晚了。因此,只需在您的 notifyDelegateCreatedObjects 方法中对下游场景的处理进行单元测试,或者由于线程计时而通知该中止事件的任何类。

我知道这不是您问题的具体答案,但我认为这是实现相同单元测试目标的更好方法。

关于ios - 如何对依赖于 Objective-C 中的 volatile 变量的方法进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21638266/

相关文章:

ios - 为什么此绘图代码在某些运行 iOS 8.1 的 iPad 上有效,而在其他 iPad 上无效?

objective-c - Cocoa:如何以模式方式显示窗口?

java - 具有多个线程的Java中的对象指针

c++ - 在 C++ 中使用 QThread 多线程编程

ios - 无法快速获取要在 UITextView 中显示的正确文件

ios - MonoTouch 中的自定义 UINavigationBar

ios - 使用 NSString 作为键和值创建 JSON 格式

ios - 滚动 tableview 后加载更多数据( Objective-C )

ios - 在 IOS 中触摸 View 时可以在触摸点上发光吗?

c# - 紧凑框架: Update of label in thread not working