web-dev-qa-db-ja.com

Swift 3の正しいディスパッチキューにあるかどうかを確認します

コールバックが正しいディスパッチキューで呼び出されるかどうかをテストするいくつかの単体テストがあります。

Swift 2で、現在のキューのラベルをテストキューと比較しました。ただし、Swift 3では、DISPATCH_CURRENT_QUEUE_LABEL定数は存在しません。

dispatch_assert_queue関数は見つかりました。それは私が必要とするもののようですが、それをどのように呼び出すかわかりません。

私のSwift 2コード:

let testQueueLabel = "com.example.my-test-queue"
let testQueue = dispatch_queue_create(testQueueLabel, nil)

let currentQueueLabel = String(UTF8String: dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))!
XCTAssertEqual(currentQueueLabel, testQueueLabel, "callback should be called on specified queue")

更新:

オートコンプリートがないことで混乱しましたが、__dispatch_assert_queueを使用することは可能です:

if #available(iOS 10.0, *) {
  __dispatch_assert_queue(test1Queue)
}

これは単体テストでは機能しますが、テストが失敗するだけでなく、EXC_BAD_INSTRUCTIONでプロセス全体がうっとうしく停止します。

20
Tom Lokhorst

私自身の質問に答える:

KFDoomのコメント に基づいて、setSpecificおよびgetSpecificを使用しています。

これにより、キーが作成され、テストキューに設定され、後で再び取得されます。

let testQueueLabel = "com.example.my-test-queue"
let testQueue = DispatchQueue(label: testQueueLabel, attributes: [])
let testQueueKey = DispatchSpecificKey<Void>()

testQueue.setSpecific(key: testQueueKey, value: ())

// ... later on, to test:

XCTAssertNotNil(DispatchQueue.getSpecific(key: testQueueKey), "callback should be called on specified queue")

キーに関連付けられている値がないことに注意してください(そのタイプはVoidです)。私は特定の値の存在ではなく、特定の値の存在にのみ関心があります。

重要!
必ずキーへの参照を保持するか、使用後はクリーンアップしてください。そうしないと、新しく作成されたキーが同じメモリアドレスを使用し、奇妙な動作を引き起こす可能性があります。参照: http://tom.lokhorst.eu/2018/02/leaky-abstractions-in-Swift-with-dispatchqueue

16
Tom Lokhorst

dispatchPrecondition(.onQueue(expectedQueue))を使用すると、Swift 3 APIの代わりにdispatch_assert_queue() C APIを使用できます。

これは、今年のWWDC GCDセッションで取り上げられました: https://developer.Apple.com/videos/play/wwdc2016/720/

26
das

KFDoomの回答 に基づくテスト:

import XCTest
import Dispatch

class TestQueue: XCTestCase {

    func testWithSpecificKey() {
        let queue = DispatchQueue(label: "label")

        let key = DispatchSpecificKey<Void>()
        queue.setSpecific(key:key, value:())

        let expectation1 = expectation(withDescription: "main")
        let expectation2 = expectation(withDescription: "queue")

        DispatchQueue.main.async {
            if (DispatchQueue.getSpecific(key: key) == nil) {
                expectation1.fulfill()
            }
        }

        queue.async {
            if (DispatchQueue.getSpecific(key: key) != nil) {
                expectation2.fulfill()
            }
        }

        waitForExpectations(withTimeout: 1, handler: nil)
    }

    func testWithPrecondition() {
        let queue = DispatchQueue(label: "label")

        let expectation1 = expectation(withDescription: "main")
        let expectation2 = expectation(withDescription: "queue")

        DispatchQueue.main.async {
            dispatchPrecondition(condition: .notOnQueue(queue))
            expectation1.fulfill()
        }

        queue.async {
            dispatchPrecondition(condition: .onQueue(queue))
            expectation2.fulfill()
        }

        waitForExpectations(withTimeout: 1, handler: nil)
    }

}
7
Silmaril

1つのオプションは、キューを直接テストするための前提条件を設定するか、キューに「特定」を設定して後で取得することです。さらに、setSpecificとgetSpecificを使用できます。または、キューにいる場合は、前提条件チェックを使用して、「最新の取得」のニーズを満たす必要があります。 src: https://github.com/duemunk/Async/blob/feature/Swift_3.0/AsyncTest/AsyncTests.Swift

そして

https://github.com/Apple/Swift/blob/master/stdlib/public/SDK/Dispatch/Dispatch.Swift

3
KFDoom