如何TDD UIGestureRecognizers?

问题描述 投票:6回答:4

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

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

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

objective-c xcode unit-testing tdd uigesturerecognizer
4个回答
4
投票

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

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

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

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


2
投票

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

First, I create an OnTap helper class

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()
  }
}

Next, I register a tap gesture wit a view and a callback 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
    }
  }
}

Finally, I simulate the tap in my unit test and check that the closure has been called

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

    obj.onTap?.didTap(UITapGestureRecognizer())

    XCTAssert(obj.didTap)
  }
}

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


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)
    }

}

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
© www.soinside.com 2019 - 2024. All rights reserved.