2017-08-27 22 views
1

私は10秒以上呼び出す必要はありません。私がこの関数を呼び出すたびに、私はタイマーを10秒にリセットします。XCTestでXcodeのタイマーをテストする

class MyClass { 
    var timer:Timer? 

    func resetTimer() { 
    self.timer?.invalidate() 
    self.timer = Timer.scheduledTimer(withTimeInterval: 10.0, repeats: false) { 
     (timer) -> Void in 
     self.performAction()   
    } 
    } 

    func performAction() { 
    // perform action, then 
    self.resetTimer() 
    } 
} 

私はperformAction()を呼び出すと、手動で10秒にタイマーをリセットすることをテストしたいと思いますが、私はそれを行うに何か良い方法を見つけるように見えることはできません。スタッビングresetTimer()は、テストが本当に機能について十分に私に言わないように感じます。何か不足していますか?

XCTest:

func testTimerResets() { 
    let myObject = MyClass() 
    myObject.resetTimer() 
    myObject.performAction() 

    // Test that my timer has been reset. 
} 

ありがとう!

+1

テストで非同期状態が発生するのを待つ場合は、 'XCTestExpectation'を使用できます。 – Rob

+0

@Robまた、myObject.timerに対するコードの効果は同期的なので、XCTestExpectationの必要はありません。 – lonesomewhistle

答えて

0

元のTimerのfireDateを保存した後、その操作が実行された後に、新しいfireDateが元のfireDateよりも遅れて設定されていることを確認しました。

func testTimerResets() { 
    let myObject = MyClass() 
    myObject.resetTimer() 
    let oldFireDate = myObject.timer!.fireDate 
    myObject.performAction() 

    // If timer did not reset, these will be equal 
    XCTAssertGreaterThan(myObject.timer!.fireDate, oldFireDate) 
} 
1

まず、refreshTimerというメンバーがいないときに、オブジェクトがどのように動作しているかわかりません。

class MyClass { 
    private var timer:Timer? 
    public var starting:Int = -1 // to keep track of starting time of execution 
    public var ending:Int = -1 // to keep track of ending time 


    init() {} 

    func invoke() { 
     // timer would be executed every 10s 
     timer = Timer.scheduledTimer(timeInterval: 10.0, target: self, selector: #selector(performAction), userInfo: nil, repeats: true) 
     starting = getSeconds() 
     print("time init:: \(starting) second") 

    } 

    @objc func performAction() { 
     print("performing action ... ") 
     /* 
     say that the starting time was 55s, after 10s, we would get 05 seconds, which is correct. However for testing purpose if we get a number from 1 to 9 we'll add 60s. This analogy works because ending depends on starting time 
     */ 
     ending = (1...9).contains(getSeconds()) ? getSeconds() + 60 : getSeconds() 
     print("time end:: \(ending) seconds") 
     resetTimer() 
    } 

    private func resetTimer() { 
     print("timer is been reseted") 
     timer?.invalidate() 
     invoke() 
    } 

    private func getSeconds()-> Int { 
     let seconds = Calendar.current.component(.second, from: Date()) 
     return seconds 
    } 

    public func fullStop() { 
     print("Full Stop here") 
     timer?.invalidate() 
    } 
} 

テスト(コメント欄で説明)

let testObj = MyClass() 
    // at init both starting && ending should be -1 
    XCTAssertEqual(testObj.starting, -1) 
    XCTAssertEqual(testObj.ending, -1) 

    testObj.invoke() 
    // after invoking, the first member to be changed is starting 
    let startTime = testObj.starting 
    XCTAssertNotEqual(startTime, -1) 
    /* 
    - at first run, ending is still -1 
    - let's for wait 10 seconds 
    - you should use async method, XCTWaiter and expectation here 
    - this is just to give you a perspective or way of structuring your solution 
    */ 
    DispatchQueue.main.asyncAfter(deadline: .now() + 10) { 
     let startTimeCopy = startTime 
     let endingTime = testObj.ending 
     XCTAssertNotEqual(endingTime, -1) 
     // take the difference between start and end 
     let diff = endingTime - startTime 
     print("diff \(diff)") 
     // no matter the time, diff should be 10 
     XCTAssertEqual(diff, 10) 

     testObj.fullStop() 
    } 

これはそれを行う方法の最善ではありません、しかし、それはあなたが閲覧できますまたはどのように流れあなたはこれを達成する必要があります:

+0

クール - 私のリフレッシュタイマーの悪い - ちょうど編集されました。 – lonesomewhistle

0

タイマーが発射するのを待っていたい場合は、期待(またはXcode 9の新しい非同期テストAPI)を使用してください。

問題は正確にテストしようとしていることです。タイマーが起動したことをテストするのではなく、タイマーのハンドラーが実際に行っていることをテストしたいと思うかもしれません。 (それは、我々がテストしなければならないものですので、おそらくあなたは、意味のある何かを実行するためにタイマーを持っています。)

WWDC 2017のビデオEngineering for Testabilityが必要なユニットテスト用のコードを設計する方法を考えなければ素敵なフレームワークを提供しています:

  • 入力を制御します。
  • 出力への可視性。および
  • 隠れた状態はありません。

あなたのテストへの入力は何ですか?そして、もっと重要なのは、出力は何ですか。ユニットテストでどのようなアサーションをテストしたいですか?

ビデオはまた、一つの賢明な使用を介して、この構造を達成するためにコードをリファクタリングかもしれない方法のいくつかの具体例を示します。

  • プロトコルおよびパラメータを、ロジックとエフェクトを分離する。

タイマーが実際に何をしているのかわからなければ、さらにアドバイスすることは難しいです。おそらくあなたはあなたの質問を編集し、明確にすることができます。

関連する問題