Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/97.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 用Kiwi测试核心数据实体的后台保存_Ios_Unit Testing_Core Data_Grand Central Dispatch_Kiwi - Fatal编程技术网

Ios 用Kiwi测试核心数据实体的后台保存

Ios 用Kiwi测试核心数据实体的后台保存,ios,unit-testing,core-data,grand-central-dispatch,kiwi,Ios,Unit Testing,Core Data,Grand Central Dispatch,Kiwi,我正在努力找出在后台线程中测试与核心数据交互的最佳方法。我有以下的类方法: + (void)fetchSomeJSON { // Download some json then parse it in the block [[AFHTTPClient sharedClient] fetchAllThingsWithCompletion:^(id results, NSError *error) { if ([results count] > 0) {

我正在努力找出在后台线程中测试与核心数据交互的最佳方法。我有以下的类方法:

+ (void)fetchSomeJSON
{
    // Download some json then parse it in the block
    [[AFHTTPClient sharedClient] fetchAllThingsWithCompletion:^(id results, NSError *error) {
        if ([results count] > 0) {

            NSManagedObjectContext *backgroundContext = //... create a new context for background insertion
            dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

            dispatch_async(background, ^{ // If I comment this out, my test runs just fine

                //... insert and update some entities
                for (NSString *str in results) {
                    NSManagedObject *object = //...
                }
            });
        }
    }];
}
我目前正在使用以下Kiwi代码测试此方法:

describe(@"MyAction", ^{

    __block void (^completionBlock)(NSArray *array, NSError *error);

    beforeEach(^{
        // Stub the http client
        id mockClient = [AFHTTPClient mock];
        [WRNAPIClient stub:@selector(sharedClient) andReturn:mockClient];

        // capture the block argument
        KWCaptureSpy *spy = [mockClient captureArgument:@selector(fetchAllThingsWithCompletion:) atIndex:0];
        [MyClass fetchSomeJSON]; // Call the method so we can capture the block
        completionBlock = spy.argument;

        // run the completion block 
        completionBlock(@[@"blah"], nil);
    })

    // If I remove the dispatch_async block, this test passes fine. 
    // If I add it in again the test fails, probably because its not waiting
    it(@"should return the right count", ^{
        // entityCount is a block that performs a fetch request count
        NSInteger count = entityCount(moc, @"Task");
        [[theValue(count) should] equal:theValue(4)];
    })

    // This works fine, but obviously I don't want to wait a second
    it(@"should return the right count after waiting for a second", ^{
        sleep(1);
        NSInteger count = entityCount(moc, @"Task");
        [[theValue(count) should] equal:theValue(4)];
    });

};

如果我删除
dispatch\u async
行,那么我可以让测试快速运行。在使用
dispatch\u async
时,让测试套件运行的唯一方法是在调用完成块后执行
sleep(1)
。使用
sleep()。我曾经尝试过使用
应该最终
,但这似乎并没有重新获取我的
计数
值。

我尝试过几种方法来解决这个问题,没有一种感觉是正确的


1)将
dispatch\u async
移动到自己的类中

+ (void)dispatchOnMainQueue:(Block)block
{
    if ([NSThread currentThread] == [NSThread mainThread]) {
        block();
    } else {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

+ (void)dispatchOnBackgroundQueue:(Block)block
{
    dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_async(background, block);
}
然后,在测试执行期间,将后台调度切换到主队列上。这是可行的,但不可预测。我也觉得很不对


2)将设置代码移动到
Kiwi
之前的
块,然后休眠主线程。这是因为
Kiwi
测试在主线程上运行,所以我们实际上是在说“在进行测试之前让后台操作发生”。我想这就是我要用的。是的,它使我的单元测试运行得更慢,但它们在应该通过的时候通过,在应该通过的时候失败

describe(@"MyAction", ^{

    __block void (^completionBlock)(NSArray *array, NSError *error);

    beforeAll(^{
        // Stub the http client
        id mockClient = [AFHTTPClient mock];
        [WRNAPIClient stub:@selector(sharedClient) andReturn:mockClient];

        // capture the block argument
        KWCaptureSpy *spy = [mockClient captureArgument:@selector(fetchAllThingsWithCompletion:) atIndex:0];
        [WRNTaskImporter importAllTasksFromAPI];
        completionBlock = spy.argument;

        // run the completion block 
        completionBlock(@[@"blah"], nil);

        // Wait for background import to complete
        [NSThread sleepForTimeInterval:0.1];

    })

    // This works 
    it(@"should return the right count", ^{
        // entityCount is a block that performs a fetch request count
        NSInteger count = entityCount(moc, @"Task");
        [[theValue(count) should] equal:theValue(4)];
    })
};
这种方法的警告是,只有在测试前不更改任何数据时,它才起作用。例如,假设我插入4个实体,并希望检查每个实体是否按预期插入。这个选项在这里会起作用。如果需要重新运行导入方法并检查计数是否增加,则需要在调用插入代码后添加另一个
[NSThread sleepForTimeInterval:0.1]


对于基于正常块的
Kiwi
测试,您可能应该使用
expectFutureValue-shouldneally
方法或
KWCaptureSpy
来测试代码,但这在调用嵌套块时可能没有帮助


如果有人有一个更合适的方法来测试像这样的案例,我很高兴听到它

我尝试了几种方法来解决这个问题,但没有一种是正确的


1)将
dispatch\u async
移动到自己的类中

+ (void)dispatchOnMainQueue:(Block)block
{
    if ([NSThread currentThread] == [NSThread mainThread]) {
        block();
    } else {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

+ (void)dispatchOnBackgroundQueue:(Block)block
{
    dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_async(background, block);
}
然后,在测试执行期间,将后台调度切换到主队列上。这是可行的,但不可预测。我也觉得很不对


2)将设置代码移动到
Kiwi
之前的
块,然后休眠主线程。这是因为
Kiwi
测试在主线程上运行,所以我们实际上是在说“在进行测试之前让后台操作发生”。我想这就是我要用的。是的,它使我的单元测试运行得更慢,但它们在应该通过的时候通过,在应该通过的时候失败

describe(@"MyAction", ^{

    __block void (^completionBlock)(NSArray *array, NSError *error);

    beforeAll(^{
        // Stub the http client
        id mockClient = [AFHTTPClient mock];
        [WRNAPIClient stub:@selector(sharedClient) andReturn:mockClient];

        // capture the block argument
        KWCaptureSpy *spy = [mockClient captureArgument:@selector(fetchAllThingsWithCompletion:) atIndex:0];
        [WRNTaskImporter importAllTasksFromAPI];
        completionBlock = spy.argument;

        // run the completion block 
        completionBlock(@[@"blah"], nil);

        // Wait for background import to complete
        [NSThread sleepForTimeInterval:0.1];

    })

    // This works 
    it(@"should return the right count", ^{
        // entityCount is a block that performs a fetch request count
        NSInteger count = entityCount(moc, @"Task");
        [[theValue(count) should] equal:theValue(4)];
    })
};
这种方法的警告是,只有在测试前不更改任何数据时,它才起作用。例如,假设我插入4个实体,并希望检查每个实体是否按预期插入。这个选项在这里会起作用。如果需要重新运行导入方法并检查计数是否增加,则需要在调用插入代码后添加另一个
[NSThread sleepForTimeInterval:0.1]


对于基于正常块的
Kiwi
测试,您可能应该使用
expectFutureValue-shouldneally
方法或
KWCaptureSpy
来测试代码,但这在调用嵌套块时可能没有帮助


如果有人有一个更合适的方法来测试像这样的案例,我很高兴听到它

我尝试了几种方法来解决这个问题,但没有一种是正确的


1)将
dispatch\u async
移动到自己的类中

+ (void)dispatchOnMainQueue:(Block)block
{
    if ([NSThread currentThread] == [NSThread mainThread]) {
        block();
    } else {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

+ (void)dispatchOnBackgroundQueue:(Block)block
{
    dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_async(background, block);
}
然后,在测试执行期间,将后台调度切换到主队列上。这是可行的,但不可预测。我也觉得很不对


2)将设置代码移动到
Kiwi
之前的
块,然后休眠主线程。这是因为
Kiwi
测试在主线程上运行,所以我们实际上是在说“在进行测试之前让后台操作发生”。我想这就是我要用的。是的,它使我的单元测试运行得更慢,但它们在应该通过的时候通过,在应该通过的时候失败

describe(@"MyAction", ^{

    __block void (^completionBlock)(NSArray *array, NSError *error);

    beforeAll(^{
        // Stub the http client
        id mockClient = [AFHTTPClient mock];
        [WRNAPIClient stub:@selector(sharedClient) andReturn:mockClient];

        // capture the block argument
        KWCaptureSpy *spy = [mockClient captureArgument:@selector(fetchAllThingsWithCompletion:) atIndex:0];
        [WRNTaskImporter importAllTasksFromAPI];
        completionBlock = spy.argument;

        // run the completion block 
        completionBlock(@[@"blah"], nil);

        // Wait for background import to complete
        [NSThread sleepForTimeInterval:0.1];

    })

    // This works 
    it(@"should return the right count", ^{
        // entityCount is a block that performs a fetch request count
        NSInteger count = entityCount(moc, @"Task");
        [[theValue(count) should] equal:theValue(4)];
    })
};
这种方法的警告是,只有在测试前不更改任何数据时,它才起作用。例如,假设我插入4个实体,并希望检查每个实体是否按预期插入。这个选项在这里会起作用。如果需要重新运行导入方法并检查计数是否增加,则需要在调用插入代码后添加另一个
[NSThread sleepForTimeInterval:0.1]


对于基于正常块的
Kiwi
测试,您可能应该使用
expectFutureValue-shouldneally
方法或
KWCaptureSpy
来测试代码,但这在调用嵌套块时可能没有帮助


如果有人有一个更合适的方法来测试像这样的案例,我很高兴听到它

我尝试了几种方法来解决这个问题,但没有一种是正确的


1)将
dispatch\u async
移动到自己的类中

+ (void)dispatchOnMainQueue:(Block)block
{
    if ([NSThread currentThread] == [NSThread mainThread]) {
        block();
    } else {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

+ (void)dispatchOnBackgroundQueue:(Block)block
{
    dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_async(background, block);
}
然后,在测试执行期间,将后台调度切换到主队列上。这是可行的,但不可预测。我也觉得很不对


2)将设置代码移动到
Kiwi
之前的
块,然后休眠主线程。这是因为
Kiwi
测试在主线程上运行,所以我们实际上是在说“在进行测试之前让后台操作发生”。我想这就是我要用的。是的,它使我的单元测试运行得更慢,但是当它们运行时,它们通过了