Getting runtime exception while unit testing UIDatePicker ([UIPickerColumnView isDragging:] unrecognized selector)

599 Views Asked by At

I created a UIViewController with a UIDatePicker outlet, corresponding nib file, and correctly set the outlet in interface builder.

I'm trying to run the following unit test (using OCHamcrest matcher library).

- (void)test___datePicker___shouldBeConnected
{
  [sut view];
  assertThat(sut.datePicker, is(notNilValue()));
}

Where sut (for "system under test") is the view controller being unit tested.

However, I keep getting this runtime exception:

[UIPickerColumnView isDragging]: unrecognized selector sent to instance 0x10dcdcc70

Where UIPickerColumnView is not a class I created (it appears to be a non-public class used in UIKit).

I've tried removing the UIDatePicker from the nib and creating it programmatically:

- (void)viewDidLoad
{
  [super viewDidLoad];

  UIDatePicker *datePicker = [[UIDatePicker alloc] init];
  [datePicker setDate:[NSDate date]];
  [datePicker addTarget:self action:@selector(dateChanged:)
   forControlEvents:UIControlEventValueChanged];
  [self.view addSubview:datePicker];
}

However, the same exception occurs.

With breakpoint on exception, here is the error thread:

#0  0x0000000100857973 in objc_exception_throw ()
#1  0x0000000100c8065d in -[NSObject(NSObject) doesNotRecognizeSelector:] ()
#2  0x0000000100be0d8d in ___forwarding___ ()
#3  0x0000000100be0938 in __forwarding_prep_0___ ()
#4  0x00000001066c5b6e in -[UIPickerView _sendSelectionChangedFromTable:notify:] ()
#5  0x00000001066c5fec in -[UIPickerView _selectRow:inComponent:animated:notify:] ()
#6  0x0000000106c7bac7 in -[_UIDatePickerView _selectRow:inComponent:animated:notify:] ()
#7  0x0000000106c81c3f in -[_UIDatePickerMode loadDate:animated:] ()
#8  0x0000000106c85456 in -[_UIDatePickerMode_DateAndTime loadDate:animated:] ()
#9  0x0000000106c7ba8b in -[_UIDatePickerView _loadDate:animated:] ()
#10 0x0000000106c7b26b in -[_UIDatePickerView _setDate:animated:forced:] ()
#11 0x0000000106911c0e in -[UIDatePicker initWithCoder:] ()
#12 0x0000000106a6a794 in UINibDecoderDecodeObjectForValue ()
#13 0x0000000106a6a4df in -[UINibDecoder decodeObjectForKey:] ()
#14 0x000000010692e198 in -[UIRuntimeConnection initWithCoder:] ()
#15 0x0000000106a6a794 in UINibDecoderDecodeObjectForValue ()
#16 0x0000000106a6a95c in UINibDecoderDecodeObjectForValue ()
#17 0x0000000106a6a4df in -[UINibDecoder decodeObjectForKey:] ()
#18 0x000000010692d7b6 in -[UINib instantiateWithOwner:options:] ()
#19 0x00000001067c7b0c in -[UIViewController _loadViewFromNibNamed:bundle:] ()
#20 0x00000001067c8149 in -[UIViewController loadView] ()
#21 0x00000001067c83b7 in -[UIViewController loadViewIfRequired] ()
#22 0x00000001067c8777 in -[UIViewController view] ()
#23 0x0000000102e01c86 in -[AODateTimeDetailViewControllerTests test___datePicker___ShouldBeConnected] at /Users/Anthony/Documents/AORepos/AOReportControllers/AOReportControllersTests/AODateTimeDetailViewControllerTests.m:43
#24 0x0000000100be4f1c in __invoking___ ()
#25 0x0000000100be4dc4 in -[NSInvocation invoke] ()
#26 0x0000000102cb9c40 in -[XCTestCase invokeTest] ()
#27 0x0000000102cb9d2c in -[XCTestCase performTest:] ()
#28 0x0000000102cbaa75 in -[XCTest run] ()
#29 0x0000000102cb94df in -[XCTestSuite performTest:] ()
#30 0x0000000102cbaa75 in -[XCTest run] ()
#31 0x0000000102cb94df in -[XCTestSuite performTest:] ()
#32 0x0000000102cbaa75 in -[XCTest run] ()
#33 0x0000000102cb94df in -[XCTestSuite performTest:] ()
#34 0x0000000102cbaa75 in -[XCTest run] ()
#35 0x0000000102cbc1b4 in +[XCTestProbe runTests:] ()
#36 0x00000001000012e1 in ___lldb_unnamed_function9$$xctest ()
#37 0x0000000100001521 in ___lldb_unnamed_function11$$xctest ()
#38 0x0000000100001017 in ___lldb_unnamed_function2$$xctest ()

How can I prevent this exception from being thrown while unit testing UIDatePicker?

1

There are 1 best solutions below

1
On

I can confirm this behavior with UIDatePicker while unit testing, and it seems other iOS developers are having this issue too (https://discussions.apple.com/message/25373309).

Unfortunately, this appears to be a bug in the iOS 7 SKD (Xcode 5.1). However, it seems to be fixed in the iOS 8 SDK (Xcode 6 beta 1).

This exception is thrown if you access a UIViewController's view property and it contains a UIDatePicker, which is how you usually cause the view and its outlets to be setup during unit testing.

Here's the solution I'm using to get around it:

@interface YourViewControllerTests
@end

@implementation YourViewControllerTests
{
  YourViewController *sut;
  UIDatePicker *datePicker;
}

- (void)setUp
{
  [super setUp];

  sut = [[YourViewController alloc] initWithNibName:@"YourViewController" bundle:[NSBundle bundleForClass:[self class]]];
  [self givenViewSetup];
}

- (void)givenViewSetup
{
  @try {
    [sut view];
  }
  @catch (NSException *exception) {
    // ignore the exception
  }
  @finally {
    datePicker = [[UIDatePicker alloc] init];
    sut.datePicker = datePicker;
  }
}

- (void)test___datePicker___shouldBeConnected
{
  assertThat(sut.datePicker, is(notNilValue()));
}

@end

While your UIDatePicker outlet isn't technically unit tested now, at least you can continue with the rest of the tests for your view controller.

Of course, make sure to drop this try-catch nonsense as soon as you make the switch to Xcode 6! :]