UIApp is nil which means we cannot dispatch control actions to their targets

I was changing file from one module to another, doing so I start getting this error in one of my tests. While earlier it was working absolutely fine.

[Assert] UIApp is nil which means we cannot dispatch control actions to their targets. If this assert is hit, we probably got here without UIApplicationMain() being executed, which likely means this code is not running in an app (perhaps a unit test being run without a host app) and will not work as expected.

In code add button in viewDidLoad()

    private lazy var button: ABCTypeButton = {
        let button = ABCTypeButton(title: viewModel.title, buttonType: .Payment).withAutoLayout()
        button.accessibilityLabel = viewModel.title
        button.accessibilityIdentifier = "paymentButton"
        button.resetTintColor()
        button.addTarget(self, action: #selector(ABCViewController.action1), for: .touchUpInside)
        button.addTarget(self, action: #selector(ABCViewController.action2), for: .touchDown)
        button.addTarget(self, action: #selector(ABCViewController.action3), for: [.touchUpOutside, .touchDragExit])
        return button
    }()

@objc private func action1() {
// code
}

public class ABCTypeButton: UIControl {

let iconImageView = UIImageView()
let buttonTitleLabel = UILabel()
private let chevronImageView = UIImageView(image: Icon.navigateNext.image)
private let stackView = UIStackView().withAutoLayout()

public init(title buttonTitle: String,
            buttonType: FeeButtonType,
            height: CGFloat = Spacing.four) {
    super.init(frame: CGRect.zero)
    setupViews(buttonTitle, buttonType: buttonType)
    setupConstraints(height: height)
} 
}

Trying to tap button from tests.

    func test() {
    let viewController = ViewController(viewModel: viewModel)
    let button = viewController.view.findViewByIdentifier("paymentButton") as! ABCTypeButton
    // I Checked that button is not nil
    button.sendActions(for: .touchUpInside)
    XCTAssertEqual(viewController.value, button.accessibilityIdentifier)
}

Target method action1() is not getting called


Solution 1:

i just ran into this, and made this rough extension for the touchUpInside event. can obviously be refactored to take in whatever events you'd like to call.

extension UIButton {
  public func touchUpInside(forTarget target: UIViewController) {
    guard let action = actions(forTarget: target, forControlEvent: .touchUpInside)?.first else {
      assertionFailure("could not find touchUpInside action for target")
      return
    }

    target.perform(Selector(action))
  }
}