How to write unit test for button tap?
Asked Answered
F

5

6

Here I'm trying to check unit test cases for view controller. - I have a view controller with button and label. - When you click on the button, it will call another method. which feeds the data to the button action label text change.
- I want to check that button triggered that method or not? without adding any boolean or return type of the function.

Here is my code.

class ViewController: UIViewController {

    @IBOutlet weak var buttonFetch: UIButton?

    @IBOutlet weak var nameLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    @IBAction func fetchUser() {
        self.nameLabel.text = self.getUser()
    }

    func getUser() ->String {
        return User.data()
    }
}

struct User  {
    static func data()->String{
        return "Apple"
    }
}

Here is my test case

func testFetchUserAction() {
        controller.buttonFetch?.sendActions(for: .touchDown)
        // I want to test the method getUser from viewcontroller gets called or not
        // some thing like this XCTAssert(self.controller.getUser(),"not called")
        XCTAssertEqual(self.controller.nameLabel.text!, "Apple")

    }
Femineity answered 13/12, 2018 at 6:52 Comment(5)
Why you do not use XCUITest for ui testing like button is clicked or not ?Prostitute
@JatinKathrotiya Unit tests are much faster than UI tests.Melodramatize
Then your goals are self contradictory. Unit tests test business logic. If you want to test that tapping a button has a certain effect, that’s an UI test.Indiraindirect
@Indiraindirect Unit test test whatever you want them to. Don't limit yourself. I live on unit testing view controllers. qualitycoding.org/testing-view-controllersMelodramatize
Worthwhile argument for sure.Indiraindirect
Z
4

Have you tried as like below..

func testFetchUserAction() {

    self.controller.nameLabel.text = nil

    //Use this line, If you assigned touchUpInside to your button action
    controller.buttonFetch?.sendActions(for: .touchUpInside)

    //Use this line, If you assigned touchDown to your button action
    controller.buttonFetch?.sendActions(for: .touchDown)

    XCTAssert(self.controller.nameLabel.text != nil, "not called")

}

Note: To make test case failed purposely, you can change UIControl.Event in sendActions

Zed answered 13/12, 2018 at 8:17 Comment(0)
M
4

What you're missing:

Make sure to call loadViewIfNeeded() somewhere.

This can be in the test, or in setUp(). This will load your outlets, and call viewDidLoad().

Then, as much as possible, test the result of invoking an action, instead of whether or not a method was called. You've done this in your example assertion.

I'd also add that the correct action for buttons is almost always .touchUpInside, not .touchDown. This allows the user to press a button, then drag away to change their mind. "I don't want to push this after all."

Melodramatize answered 14/12, 2018 at 20:49 Comment(0)
R
1

Found something similar on another response, attempted something like this? Source: How to add tap action for button in "Unit Testing" and show Alert

func testTappingLoginButton_ShouldPresentAlert() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sut = storyboard.instantiateInitialViewController() as! ViewController
    sut.loadViewIfNeeded()
    let alertVerifier = QCOMockAlertVerifier()

    sut.loginButton.sendActions(for: .touchUpInside)

    XCTAssertEqual(alertVerifier.presentedCount, 1)
}

Let me know if it works or not!

Renarenado answered 13/12, 2018 at 6:59 Comment(0)
F
0

I have tried like below, its passed the test. But I'm not sure it is correct or not?

XCTAssertNotNil(self.controller!.getUser, "get user method not called")
Femineity answered 13/12, 2018 at 7:14 Comment(1)
Don't post updates to your question as an answer to you question. And please read how to ask good questions.Arianism
C
0

Fake tap action on a button for UIViewController testing.

By using this helper, tap(_:), you can verify if your button perform the @IBAction you were expecting when testing your ViewController.

public func tap(_ button: UIButton) {
  button.sendActions(for: .touchUpInside)
}
// Button in your UIViewController
@IBOutlet weak var primaryButton: UIButton!

// In your XCTest subclass
var sut: UIViewController!

tap(sut.primaryButton) // example of use in your test() function
Contingence answered 29/10, 2021 at 9:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.