2017-10-11 6 views
2

コード構造を単純化すると、UIViewControllerviewDidLoad()があり、DispatchQueue.main.async()を使用するメソッドを呼び出して、メインスレッドがコードを実行するまで待機します。このテストは堅牢ですか?ユニットテストでDispatchQueue.main.async()を使用できますか?

viewDidLoad() { 
    method() 
} 

method() { 
    ... 
    DispatchQueue.main.async() { 
     ...some code... 
    } 
} 

私のテストでは、XCTAssertEqualを呼び出す前にメインスレッドを待つ必要があります。

func testSuccessRequest() { 
     let exp = expectation(description: "labelText") 
     let vc = ViewController.init() 
     vc.request = SuccessRequest.init() 
     vc.loadViewIfNeeded() 

     DispatchQueue.main.async() { 
      XCTAssertEqual(vc.label.text, "success") 
      exp.fulfill() 
     } 

     waitForExpectations(timeout: 40, handler: nil) 
} 

このテストは堅牢ですか?または、アサーションコードが非同期の前に呼び出される状況がありますか?あなたは右vc.loadViewIfNeeded(後

DispatchQueue.main.async() { 
      XCTAssertEqual(vc.label.text, "success") 
      exp.fulfill() 
     } 

を呼び出す場合の方法以来

答えて

0

は()あなたは、非同期メソッド()の呼び出しが完了される前にテストケースの期待は完全な塗りつぶしを取得することを保証するものではありません)のテスト中ので非同期であります。 上記の両方のメソッド()(&)は非同期です。

しかし、あなたが行うことができますです - fulが以下のようないくつかの時間後にテストケースの期待を埋める:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
      XCTAssertEqual(vc.label.text, "success") 
      [expectation fulfill]; 
      }); 

waitForExpectations(timeout: 40, handler: nil) 

これは、あなたがGCDを使用している非同期メソッドをテストすることができます1つの方法です。それが役に立てば幸い。

編集: 上記の戦略では2秒待つことができますが、このシナリオでは、より良い方法が実装できます。

XCTKVOExpectationとXCTWaiterクラスは、XCTestフレームワークで利用できます。ここではそれらについての簡単な説明です:

  • XCTKVOExpectation Cretes観察 オブジェクトの「キーパス」で埋めいっぱいです期待
  • XCTWaiter が期待タイムアウトが比較より説明戻り値を提供します通常waitForExpectations(タイムアウト:,ハンドラー:)これは単純にエラーをスローします。

あなたのテストケースは次のようになります。

func testSuccessRequest() {    
     let promise = XCTKVOExpectation(keyPath: "text", object: vc.label, 
               expectedValue: "success") 
     let vc = ViewController.init() 
     vc.request = SuccessRequest.init() 
     vc.loadViewIfNeeded() 
     let result = XCTWaiter().wait(for: [promise], timeout: 40) 
     XCTAssertTrue(result == .completed) 
    }  

ここでは、KVO exp。 labelの "text"プロパティー上に作成され、ビューに非同期呼び出しがロードされてから、テストケースがタイムアウトするまでしばらく待機します。次に、XCTWaiterから戻り値をアサートすることができます。

希望します。

+0

こんにちは、2秒の遅延を使用しています。しかし、ほんとうの回避策ではありませんか?ランダム遅延値を設定するだけでテストを遅らせる必要はありません。 – aneuryzm

+0

ありがとうございます。あなたのソリューションは機能していて、非同期スレッドを扱っているときに定期的に使用できるように思えます。私は思っていた:どのように共通の問題ですか?あなたはそれについて少し考えなければならなかったようです。しかし、UILabelが非同期に更新されることはあまり一般的ではありませんか?言い換えれば、あなたが私に与えた解決策はどれほど共通点ですか? – aneuryzm

+0

これはコールバックを返さないGCD関数またはKVOの一般的な問題です。これらは有用なシナリオです。私は本当に私の前で改善しなければなりませんでした。私たちは故意に遅れています。 – manismku

関連する問題