2017-05-19 4 views
1

このコードを標準のMVCプロジェクトで実行すると、すべて正常に動作します。プログラムでUISliderにアクションを送信できます。UISlider addTargetとsendActionsがUTで動作しない

override func viewDidLoad() { 
    super.viewDidLoad()   
    slider = UISlider(frame: CGRect(x: 100, y: 100, width: 200, height: 50)) 
    slider.minimumValue = 1 
    slider.maximumValue = 100 
    slider.addTarget(self, action: #selector(sliderTouch), for: .touchUpInside) 
    slider.sendActions(for: .touchUpInside) 
} 

func sliderTouch(sender: UISlider) { 
    print("value: \(sender.value)") 
} 

私のUTでスライダー動作をシミュレートしたいときは、何らかの理由で動作しません。ここでのコードは次のとおりです。

func testSlider() { 
    let slider = UISlider(frame: CGRect(x: 100, y: 100, width: 200, height: 50)) 
    slider.minimumValue = 1 
    slider.maximumValue = 100 
    slider.addTarget(self, action: #selector(sliderTouch), for: .touchUpInside) 
    slider.sendActions(for: .touchUpInside) 
} 

func sliderTouch(sender: UISlider) { 
    print("value: \(sender.value)") 
} 

sliderTouch()はUTの場合には、私の理解から呼び出されることはありません、sendActionsはasnycではなく、直接アクションメソッドを呼び出す必要があります。

なぜこの動作が発生していますか?これをどのように解決できますか?迅速な3については、私もそのようなUISwitchUISegmentedControlUIDatePickerなどなど、他のUIKitコントロールのために働く必要があります...

+0

あなたはタッチを捕まえたいですか? –

+0

このテストはコンポーネントのUIKitで提供されているアクションディスパッチの機能とどのように関係していますか?タッチ操作をテストしたい場合は、 'sliderTouch(sender:slider)'のようにアクションメソッドを直接呼び出すことができます。 (それはあなたの 'testSlider'テスト機能が通過するので、常に、実際のテストアサーションを持っていないこと、これを明確に役立ちません。) –

+0

JeremyW.Sherman @私のユースケースは、上記のスニペットではありません。私はちょうど主な問題が何であるかを示すスニペットを書いた。実際には、特定の方法でアクションディスパッチに反応するライブラリ内にカスタムスライダがあり、その動作が正しいことをテストしたい。上記のスニペットでアサーションを書いていないので、私はあなたを混乱させずに問題をクリアにしてみてください:) –

答えて

2

Frameworkターゲットに含まれるクラスをテストするときに、私はあなたと同じ問題がありました。ここ

Apple's documentationからの抜粋である:

コントロール固有のイベントが発生すると、制御はすぐに関連するアクションメソッドを呼び出します。アクションメソッドは、現在のUIApplicationオブジェクトを介してディスパッチされます。このオブジェクトは、必要に応じてレスポンダチェーンに続いて、メッセージを処理するための適切なオブジェクトを検出します。

フレームワークのクラスをテストする場合そこにはUIApplicationオブジェクトがなく、従って、イベントがディスパッチすることができません。

テストターゲット設定にホストアプリケーションを追加できます。ホストアプリケーションがない場合は、空のiOSアプリケーションを作成して使用するだけです。

this postも参照してください。

アップデート:ドロップダウンでのアプリケーションが存在しない場合、単純に新しいターゲットを作成し、を使用し、

Xcode Screenshot

:ここ

ホストアプリケーションを設定する方法ですアプリケーション>シングルビューアプリケーションテンプレート。

あなたが行われており、あなたのテストが機能するようになりました。追加の手順はありません。

+0

これはスポットです!私はこのホストアプリケーションを追加することに目を向けます。それがうまくいくなら、私は正しいとマークします –

+0

Vasilii Muravevは彼の答えのコメントにアプローチを指摘し、ReactiveCocoaによって採用されたようです。それは私のために働いた。あなたのアプローチはより良いと思いますか?私はそれを行う簡単な方法を見つけることができなかったので、私に教えてください。 いずれにしても、あなたの答えは「なぜそれが働いていないのか」に対する答えを正しく与えてくれました。もう一度お返事ありがとうございます。 –

+0

もちろん、どのトピックでも、それぞれのアプローチには利点と欠点があります。だからこそ、私のソリューションは、追加のコードに依存しないため、望ましい解決策にすべきだと思います。方法swizzlingは非常に強力なものですが、何が起こっているかを完全に理解していない場合** **落とし穴がたくさんあります。また、同じコードを扱っている他のチームメンバーにとって、UIKitメソッドは、実装を交換したために実際に行うことが実際には行われない状況にあることは非常に驚くかもしれません。 – naglerrr

1

編集 https://github.com/ReactiveCocoa/ReactiveCocoa/blob/ae6ebb7725b3d5d33db039d456797c220720cb99/ReactiveCocoaTests/UIKit/UIControl%2BEnableSendActionsForControlEvents.swift

スウィフト2については https://github.com/RACCommunity/Rex/blob/master/Tests/Helpers/UIControl%2BEnableSendActionsForControlEvents.swift

またはサブクラス化を試してください:

class TouchSlider: UISlider { 
    var touchUpInsideHandler: ((TouchSlider) -> Void)? 

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 
     touchUpInsideHandler?(self) 
     guard let touch = touches.first, 
       let imageWidth = currentThumbImage?.size.width else { 
      super.touchesBegan(touches, with: event) 
      return 
     } 
     let location = touch.location(in: self) 
     let newValue: Float = minimumValue + (maximumValue - minimumValue) * Float((location.x - imageWidth/2.0)/(bounds.width - imageWidth)) 
     setValue(newValue, animated: true) 
     super.touchesBegan(touches, with: event) 
    } 
} 

touchUpInsideHandlerを使用して外部のタッチを管理します。

+0

ソリューションをありがとう。私が恐れているのは、 'UISlider'をシミュレートするだけでなく、' UIDatePicker'、 'UISwitch'などをシミュレートする必要があることです。それは単純な問題のサブクラス化と定型句の多くになると思いませんか? –

+0

@GuyDhaherあなたは具体的に質問する必要があります)「なぜ私はこの動作をしていますか?これをどのように解決できますか?」 –

+0

あなたは正しくありません。私はすべてのUIKitコントロールに適用できる解決策があると思いました。私は質問を編集します、それを指摘してくれてありがとうと申し訳ありませんが、再び –

関連する問題