OCHamcrest
Hamcrest for Objective-C: Powerful, combinable, extensible matchers for verification
Hamcrest hamcrest
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
?
Source: (StackOverflow)
Good day,
I'm using OCHamcrest and OCMockito to start my path using TDD methodology, they really cool tools but there's one thing that it seems that I don't understand about mocking a protocol and try to evaluate a parameter.
Considering the example that comes with the code:
- (void)testVerifyWithMatcherForPrimitive
{
NSMutableArray *mockArray = mock([NSMutableArray class]);
[mockArray removeObjectAtIndex:2];
[[verify(mockArray) withMatcher:greaterThan([NSNumber numberWithInt:1]) forArgument:0]
removeObjectAtIndex:0]; // The 0 is a placeholder, replaced by the matcher
}
It works like expected, but when I try to replicate this with a mock protocol it always pass the tests, for example:
- (void)testFirstParameter
{
// given
id<TestProtocol> mockElement = mockProtocol(@protocol(TestProtocol));
// when
id toProcess = nil;
[mockElement process: toProcess];
// then
id firstArgumentMatcher = instanceOf([NSArray class]);
[[verify(mockElement) withMatcher: firstArgumentMatcher forArgument: 0] process: toProcess];
}
In this test I'm trying to test that the argument is instance of an NSArray class, it shouldn't pass. Could you help me to detect what I'm doing wrong?
Thank you very much,
Luis Alejandro
Source: (StackOverflow)
In using OCMockito, the below works great:
DSAPIManager *mockAPIManager = mock([DSAPIManager class]);
[given([mockAPIManager initWithBaseURL:[mockAPIManager baseURL]]) willReturn:[DSAPIManager sharedAPIManager]];
However when I try the same thing on a method with multiple arguments (see code below), I get an "Argument type 'void' is incomplete' compiler error.
DSAPIManager *mockAPIManager = mock([DSAPIManager class]);
[given([mockAPIManager setLoginCredentialsWithEmail:@""
password:@""]) willReturn:@""];
Does anyone know the right way to go about this?
Edit
My original intent in asking this question was to resolve an issue of getting a compiler error when I try the following:
[given([mockAPIManager setLoginCredentialsWithEmail:@"" password:@""]) willDo:^id(NSInvocation *invocation) {
// Mock implementation goes here
}];
The method signature of the method I'm trying to mock is:
- (void)setLoginCredentialsWithEmail:(NSString *)email password:(NSString *)password;
What I'm actually trying to do is to mock out the implementation of a void
method. (Given a void
method, mock out the implementation of the method with a block. For my purposes the method returns a completion block, that takes in two arguments. I would like to construct those two arguments and then run the completion block inside of the mocked out implementation block.)
Source: (StackOverflow)
I have a unit test:
- (void)testFetchTrackByTrackIdIsATrack
{
[self addTrackWithSongId:@"123"];
Track *fetchedTrack = [self.library trackByTrackId:@"123"];
assertThat(fetchedTrack, instanceOf([Track class]));
}
Which fails with:
file:///Users/elliot/Development/Hark/HarkTests/TestLibrary.m: test failure:
-[TestLibrary testFetchTrackByTrackIdIsATrack] failed: Expected an instance
of Track, but was Track instance <Track: 0x6180001077d0>
I have several other tests that use the same instance checking on different classes that work - but I can't workout why this doesn't work. Delving deeper:
- (void)testFetchTrackByTrackIdIsATrack
{
[self addTrackWithSongId:@"123"];
Track *fetchedTrack = [self.library trackByTrackId:@"123"];
Class c1 = [fetchedTrack class];
Class c2 = [Track class];
}
Debugger reports:
c1 Class Track 0x0000000100012fe0
c2 Class 0x1000b3eb8 0x00000001000b3eb8
Notice how it can't see that [Track class]
is a class of type Track
? When I apply this same logic to other unit tests that are passing they both report the correct class name.
It feels like it doesn't have the class metadata at runtime, but why?
Some more cases:
assertTrue(c1 == c2); // FAIL
assertThat([fetchedTrack classDescription],
equalTo([Track classDescription])); // PASS
assertTrue([fetchedTrack isKindOfClass:[Track class]]); // FAIL
Source: (StackOverflow)
Has anyone successfully got OCHamcrest working with Kiwi? I have started a Kiwi project then I added OCHamcrest framework and got a successful build.
However when I tried to assert a condition in my Kiwi test file using hamcrest:
it(@"has 3 elements.", ^{
assertThat(stack, hasCountOf(3)); <------ this line is in hamcrest format
// [[stack should] haveCountOf:3];
});
my test would not run. It just froze and I had to kill it manually.
Mainly I want to stick to OCMockito as I am familiar with it and love it (not so much about OCHamcrest).
I was wondering if anyone can help me with this?
Source: (StackOverflow)
I frequently use OCMock with the excellent OCHamcrest matchers. But I often encounter test failure messages that aren't as helpful as they could be. This is because the OCHamcrest output relies heavily on the value returned by the "description" method of objects but OCMockObject's default description implementation is very generic.
Is there a recommended way to have mock objects return a custom description?
I've tried stubbing the "description" method on my mock objects but that doesn't seem to work.
As a workaround I've created a OCClassMockObject+Description
category extension that adds a setMockDescription:
method, but I'm hoping there's a more officially supported solution. (If not, maybe I'll polish mine up and submit a pull request.)
Here are examples of some of the results I'd like to improve...
Example Assertion #1
assertThat(recommendedSong, is(mockSong1));
Failure message:
Expected <OCMockObject[SongBar]>, but was <OCMockObject[SongBar]>
Example Assertion #2
assertThat(playlist.songs, contains(mockSong1, mockSong2, nil));
Failure message:
Expected a collection containing [<OCMockObject[SongBar]>, <OCMockObject[SongBar]>], but item 0: was <OCMockObject[SongBar]>
Source: (StackOverflow)
I'm trying to write my own HCMatcher
that I can use to simply some assertions when working with a collection of objects.
Currently my test method is doing this:
__block int totalNumberOfCells = 0;
[configurations enumerateObjectsUsingBlock:^(Layout *layout, NSUInteger idx, BOOL *stop) {
totalNumberOfCells += [layout numberOfCells];
}];
assertThatInt(totalNumberOfCells, is(equalToInt(3)));
I'm going to be doing this sort of assertion in many places, so I want to simplify it down to something like this:
assertThat(configurations, hasTotalNumberOfFeedItemCells(3));
Here is my attempt at creating my own OCHamcrest matcher:
@interface HasTotalNumberOfFeedItemCells : HCBaseMatcher {
NSInteger correctNumberOfCells;
}
- (id)initWithCorrectNumberOfCells:(NSInteger)num;
@end
OBJC_EXPORT id <HCMatcher> hasTotalNumberOfFeedItemCells(int num);
@implementation HasTotalNumberOfFeedItemCells
- (id)initWithCorrectNumberOfCells:(NSInteger)num {
self = [super init];
if (self) {
correctNumberOfCells = num;
}
return self;
}
- (BOOL)matches:(id)item {
__block int totalNumberOfCells = 0;
[item enumerateObjectsUsingBlock:^(Layout *layout, NSUInteger idx, BOOL *stop) {
totalNumberOfCells += [layout numberOfCells];
}];
return totalNumberOfCells == correctNumberOfCells;
}
- (void)describeTo:(id <HCDescription>)description {
[description appendText:@"ZOMG"];
}
@end
id <HCMatcher> hasTotalNumberOfFeedItemCells(int num){
return [[HasTotalNumberOfFeedItemCells alloc] initWithCorrectNumberOfCells:num];
}
When I try to use the hasTotalNumberOfFeedItemCells()
function I get warnings and build error saying:
- Implicit declaration of function 'hasTotalNumberOfFeedItemCells' is invalid in C99
- Implicit conversion of 'int' to 'id' is disallowed with ARC
- Conflicting types for 'hasTotalNumberOfFeedItemCells'
Any help wold be much appreciated.
Source: (StackOverflow)
In my podspec for my project, I have :
s.dependency 'OCHamcrest'
I keep on getting the above error. In Pods/Headers
, I noticed the following path :
Pods/Headers/Public/OCHamcrest/OCHamcrest.h
Also, there is nothing in my HEADER SEARCH PATHS
. Has anyone run into this issue before?
Source: (StackOverflow)
I am trying to create some tests in Xcode for my view controllers, including tests to check IBOutlets and IBActions. These work fine if I am using a basic view controller + xib file, but if I use a Storyboard file then the actions don't appear to be wired up.
Here's the setup:
- (void)setUp
{
[super setUp];
UIStoryboard *settingsStoryboard = [UIStoryboard storyboardWithName:@"SettingsStoryboard" bundle:nil];
self.viewController = [settingsStoryboard instantiateViewControllerWithIdentifier:@"SettingsViewController"];
[self.viewController view];
}
And then here's the test (XCTest, OCHamcrest and OCMock, they all fail):
- (void)testPartialDatabaseRefreshButtonSelector
{
NSArray *actions = [self.viewController.partialDatabaseRefreshButton actionsForTarget:self.viewController forControlEvent:UIControlEventTouchUpInside];
// actions is nil!!
// XCTest:
XCTAssertTrue([actions containsObject:NSStringFromSelector(@selector(partialDatabaseRefreshButton_onTouchUpInside:))], @"partialDatabaseRefreshButton has no selector");
// FAILS
// OCHamcrest:
assertThat([self.viewController.partialDatabaseRefreshButton actionsForTarget:self.viewController forControlEvent:UIControlEventTouchUpInside], contains(@"partialDatabaseRefreshButton_onTouchUpInside:", nil));
// FAILS
// OCMock:
id mock = [OCMockObject partialMockForObject:self.viewController];
[[mock expect] partialDatabaseRefreshButton_onTouchUpInside:[OCMArg any]];
//simulate button press
[self.viewController.partialDatabaseRefreshButton sendActionsForControlEvents:UIControlEventTouchUpInside];
[mock verify];
// FAILS
}
It's obviously not to do with the testing framework I'm using, but to do with the fact that it thinks the buttons don't have any actions wired to them. Yet, when I run the app, the buttons work fine.
Am I missing something?
Source: (StackOverflow)