15

この質問に対する解決策を考え出す他の投稿を読みました。ただし、彼らのソリューションでは、アプリケーションをテストできるようにするために、ハック コードをアプリケーションに追加する必要があります。私にとって、クリーンなコードは単体テストよりも重要です。

アプリで dispatch_async を定期的に使用していますが、単体テストに問題があります。問題は、メイン キューで非同期に実行されているため、テストが既に完了した後にブロックが実行されることです。ブロックが実行されるまで何らかの方法で待機してから、テストを続行する方法はありますか。

単体テストのためだけにブロックに完了を渡したくありません

- (viod)viewDidLoad
{
   [super viewDidLoad];

   // Test passes on this
   [self.serviceClient fetchDataForUserId:self.userId];


   // Test fails on this because it's asynchronous
   dispatch_async(dispatch_get_main_queue(), ^{
      [self.serviceClient fetchDataForUserId:self.userId];
   });
}

- (void)testShouldFetchUserDataUsingCorrectId
{
   static NSString *userId = @"sdfsdfsdfsdf";
   self.viewController.userId = userId;
   self.viewController.serviceClient = [[OCMockObject niceMockForClass:[ServiceClient class]];

   [[(OCMockObject *)self.viewController.serviceClient expect] fetchDataForUserId:userId];
   [self.viewController view]; 
   [(OCMockObject *)self.viewController.serviceClient verify];
}
4

3 に答える 3

41

メイン ループを短時間実行して、非同期ブロックを呼び出させます。

- (void)testShouldFetchUserDataUsingCorrectId {
   static NSString *userId = @"sdfsdfsdfsdf";
   self.viewController.userId = userId;
   self.viewController.serviceClient = [[OCMockObject niceMockForClass:[ServiceClient class]];

   [[(OCMockObject *)self.viewController.serviceClient expect] fetchDataForUserId:userId];
   [self.viewController view];
   [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
   [(OCMockObject *)self.viewController.serviceClient verify];
}

これは、負荷の高いシステムで失敗する可能性があると思います. その場合は、実行ループをより長く実行する (テスト ケースが遅くなる) か、モック オブジェクトの期待が満たされるか、タイムアウトに達するまで繰り返し実行する必要があります (これには、モック オブジェクトにメソッドを追加する必要があります)。その期待が満たされているかどうかを問い合わせます)。

于 2012-09-17T17:35:24.433 に答える
10

実行を にラップしdispatch_group、グループが を介してディスパッチされたすべてのブロックの実行を終了するのを待ちdispatch_group_wait()ます。

于 2012-09-17T16:47:49.220 に答える