GOAL: I'm currently unit testing the behavior of my UISwitch when it is pressed.
ISSUE: My issue I that the sendActions(for: .valueChanged) that I use to programmatically change the UISwitch's state is not working as I imagined. It doesn't make it change from false to true (in my example).
WHAT DID I DO ?: I'm using the following path:
- I declared my UISwitch as
true - I used
sendActions(for: .valueChanged)for changing it tofalse - I finally used
XCTAssertEqual()to check if it correctly equal tofalseas expected. (I also could have usedXCTAssertFalse()to check directly if it wasfalse.
Ps: I correctly passed loadViewIfNeeded() in my setUPWithError()
QUESTION: How can I test my UISwitch ?? Maybe using UI Tests ?
CODE: Here is my code:
var sut: ViewController!
override func setUpWithError() throws {
super.setUp()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
sut = storyboard.instantiateViewController(withIdentifier: "ViewController") as? ViewController
sut.loadViewIfNeeded()
}
func testGenderButton_ShouldUpdateValueWhenPressed() {
sut.genderSwitch.isOn = true
sut.genderSwitch.sendActions(for: .valueChanged)
XCTAssertEqual(sut.genderSwitch.isOn, false, "\(sut.genderSwitch.isOn) should be equal to false")
}
This is a misunderstanding of what UIControl.sendActions(for:) is for –– it is not for telling the control to do something, it is for the control to tell its clients that something has happened.
UIControls call this method internally when an event happens – in the case of a UISwitch it calls the method with .valueChanged and .primaryActionTriggered when the user taps the switch to change its value.
The correct way to programmatically change the value of a UISwitch is to set its isOn property. However as a rule UIKit does not send events when programmatic changes are made (this is because we do not know developer intent).
Finally it is fraught with peril to unit test code that you do not own – you may be making assumptions about how things work that are incorrect or not guaranteed by the author. For something like this you probably want a UI test – using automation to tap the switch, and then verifying that your handler is called and that the data updates correctly. This more closely matches how a user interacts with your app, and avoids encoding assumptions about how a tap on a UISwitch becomes a .valueChanged event and finally a change to your data model.