如何TDD UIGestureRecognizers?

时间:2012-01-04 05:50:43

标签: objective-c xcode unit-testing tdd uigesturerecognizer

在尝试使用UIGestureRecognizer的TDD代码时,我发现没有办法以编程方式验证目标操作。没有这个,我不确定我能否正确测试它。

如果在IB中设置了手势识别器(支持iOS 5+),则在加载NIB / Storyboard时设置目标操作;如果在代码中完成它使用initWithTarget:action:,这两者都意味着没有任何模拟能够检测到目标动作。

我没有想法。如果有人成功测试了UIGestureRecognizer,我可以使用这个建议。

4 个答案:

答案 0 :(得分:4)

不幸的是,您正在尝试检查未编写测试的框架类,因此不会公开您要验证的状态。这将使您难以确定是否存在您要检查的目标 - 动作对。在这种情况下,我可以使用三个选项,其中没有一个是很好的解决方案:

您可能能够继承UIGestureRecognizer,覆盖目标操作方法以将已注册的对保存在集合中,然后可以向该类的用户公开,然后调用这些方法的超类实现。不幸的是,你只是为了让测试更容易引入新类,必须记住使用它们,并且可能必须从UIGestureRecognizer转换到你的自定义子类,具体取决于你从哪里获得手势识别器参考。

或者,您的测试可以将新版本的目标操作方法调到UIGestureRecognizer,为您提供跟踪添加目标的钩子。只需确保在完成后将原始方法实现交换回原位,或者将来的测试会出现意外行为。

最后,您可以找到一个私有API调用,它可以让您检查手势识别器上已注册的目标操作。只需确保私有API调用仅保留在测试代码中。

答案 1 :(得分:2)

这就是我在Swift中测试轻敲手势识别器的方法。测试确保执行响应轻击手势的代码。

首先,我创建一个OnTap助手类

class OnTap: NSObject {
  var closure: ()->()

  init(view: UIView, gesture: UIGestureRecognizer, closure:() -> ()) {
    self.closure = closure
    super.init()
    view.userInteractionEnabled = true
    view.addGestureRecognizer(gesture)
    gesture.addTarget(self, action: "didTap:")
  }

  func didTap(gesture: UIGestureRecognizer) {
    closure()
  }
}

接下来,我注册了一个带有视图和回调闭包的轻击手势

class MyClass {
  var onTap: OnTap?
  var didTap = false

  func setupTap() {
    let myView = UIView()
    onTap = OnTap(view: myView, gesture: UITapGestureRecognizer()) { [weak self] in
      self?.didTap = true
    }
  }
}

最后,我在单元测试中模拟了tap,并检查是否已调用闭包

class MyGestureTests: XCTestCase {
  func testRepondToGesture() {
    let obj = MyClass()
    obj.setupTap()

    obj.onTap?.didTap(UITapGestureRecognizer())

    XCTAssert(obj.didTap)
  }
}

注意,这是一种单元测试技术。此外,我使用UI测试来确保所有部分在甜蜜的和谐中协同工作。

答案 2 :(得分:1)

我建议将手势识别器子类化如下:

class PanGestureRecognizer: UIPanGestureRecognizer {

    let initialTarget: Any?
    let initialAction: Selector?

    public override init(target: Any?, action: Selector?) {
        initialTarget = target
        initialAction = action
        super.init(target: target, action: action)
    }

}

答案 3 :(得分:0)

如果有人对使用私有API的解决方案感兴趣,可以使用UIGestureRecognizer上的以下类别发送手势识别操作。正如乔纳所指出的那样,不要在生产代码中使用它。

@interface GGGestureRecognizerTarget : NSObject{
@public
  id _target;
  SEL _action;
}    
@end

@implementation GGGestureRecognizerTarget
@end

@interface UIGestureRecognizer (GGTest)     
- (void)sendActions;   
@end    

@implementation UIGestureRecognizer (GGTest)    
- (void)sendActions{
  id targets = [self valueForKey:@"_targets"];
  for (GGGestureRecognizerTarget* target in targets) {
    [self sendActionToTarget:target];
  }
}    
- (void)sendActionToTarget:(GGGestureRecognizerTarget*)recognizerTarget{
  id target = recognizerTarget->_target;
  SEL action = recognizerTarget->_action;
  [target performSelector:action withObject:self];
}    
@end