SpaceDust__
SpaceDust__

Reputation: 4914

Unit testing button click is not working

I have added a button programmatically and I have to run unit test for automation process. We dont have much UI components so we dont use UI testing bundle.

Added button in code

self.proceedButton.frame = CGRectMake(0.0, 0.0, (buttonContainerWidth * 0.75), (buttonContainerHeight * 0.3));
self.proceedButton.center = CGPointMake(self.buttonContainer.center.x, CGRectGetHeight(self.proceedButton.frame));
self.proceedButton.layer.cornerRadius = CGRectGetHeight(self.proceedButton.frame) / 2;
self.proceedButton.layer.masksToBounds = YES;
self.proceedButton.titleLabel.font = proceedFont;
[self.proceedButton addTarget:self action:@selector(onAcceptClicked) forControlEvents:UIControlEventTouchUpInside];

Test:

[vc viewDidLoad];
NSString *selector = [[vc.proceedButton actionsForTarget:vc forControlEvent:UIControlEventTouchUpInside] firstObject];
XCTAssert([selector isEqualToString:@"onAcceptClicked"]);
[vc.proceedButton sendActionsForControlEvents: UIControlEventTouchUpInside];

This fails if I comment out the [self.proceedButton addTarget:self action:@selector(onAcceptClicked) forControlEvents:UIControlEventTouchUpInside]; line so it seems the test is written correctly.

However sendActionsForControlEvents: is not entering onAcceptClicked method in the test.

Why this is happening? Is it possible that unit test is finishing before onAcceptClicked getting actually called?

Upvotes: 1

Views: 574

Answers (1)

Gordonium
Gordonium

Reputation: 3497

This could be because you are calling [vc viewDidLoad] directly, which Apple advises you not to do, presumably because a bunch of setup is performed before viewDidLoad is eventually invoked.

You should never call this method directly. The view controller calls this method when its view property is requested but is currently nil. This method loads or creates a view and assigns it to the view property.

Instead, try using XCTAssertNotNil(vc.view); at the beginning. This will try to load the view, eventually calling viewDidLoad for you and probably setting up your button so that the actions are correctly added to it.

Edit So if it helps, I've just quickly run this test and I can verify that the method onAcceptClicked is called in the view controller when the test runs.

Button setup in viewDidLoad

CGRect frame = CGRectMake(50, 40, 30, 30);
self.proceedButton = [[UIButton alloc] initWithFrame:frame];
self.proceedButton.titleLabel.text = @"button!!!!";
[self.proceedButton addTarget:self action:@selector(onAcceptClicked) forControlEvents:UIControlEventTouchUpInside];
self.proceedButton.backgroundColor = [UIColor blackColor];
[self.view addSubview:self.proceedButton];

Test

-(void)testButton {
    self.myVC = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"MyVC"];
    XCTAssertNotNil(self.myVC.view);
    NSString *selector = [[self.myVC.proceedButton actionsForTarget:self.myVC forControlEvent:UIControlEventTouchUpInside] firstObject];
    XCTAssert([selector isEqualToString:@"onAcceptClicked"]);
    [self.myVC.proceedButton sendActionsForControlEvents: UIControlEventTouchUpInside];
}

Upvotes: 1

Related Questions