I'm newcomer to Objective-C and OCMock. I created this trivial test and expect it to pass, but it fails:
-(void)testMock
{
id dataMock = [OCMockObject niceMockForClass:[NSData class]];
[[[dataMock stub] andReturn:dataMock] initWithBase64EncodedString:[OCMArg any]
options:[OCMArg any]];
NSData *ret = [dataMock initWithBase64EncodedString:#"dGVzdA=="
options:NSDataBase64DecodingIgnoreUnknownCharacters];
XCTAssertEqualObjects(dataMock, ret);
}
As you see, I stub a method and command it to return dataMock, but it returns null:
Assertions: ((dataMock) equal to (ret)) failed:
("OCMockObject(NSData)") is not equal to ("(null)")
Note: Testing with init instead of initWithBase64EncodedString, works as expected and passes.
I'm using XCode 6.0.1 and programming for iOS 8.0.
I found out that this the famous problem of matching primitives in OCMock. options in the mentioned method, takes a primitive and [OCMArg any] does not match it.
So for now I'm going with the exact used value:
[[[dataMock stub] andReturn:dataMock] initWithBase64EncodedString:[OCMArg any]
options:NSDataBase64DecodingIgnoreUnknownCharacters];
Related
I am trying to use OCMock library. I am trying to create mock of class object, but it is failing to verify the method. I am unable to understand why the tests are failing.
#interface MyClass:NSObject
+(void) someMethod;
#end
#implementation MyClass
+(void) someMethod
{
NSError* error = nil;
if (![Utility isValidPropWithError:&error])
{
[Logger log:LoggerLevelWarning message:[error localizedDescription] className:className];
}
}
#end
Test :
-(void)testIfLoggerIsset{
id partialMockLogger = OCMClassMock([Logger class]);
id partialMockUtility = OCMClassMock([Utility class]);
id partialMockClass = OCMClassMock([MyClass class]);
NSError *error = nil;
OCMExpect([partialMockUtility isValidPropWithError:&error]);
[MyClass someMethod];
//This works fine.
OCMVerifyAll(partialMockClass);
NSString *className = #"classname";
//This is failing...
OCMVerify([partialMockUtility isValidPropWithError:&error]);
OCMVerifyAll(partialMockUtility);
//This is failing...
OCMVerify([partialMockLogger log:LoggerLevelWarning message:[error localizedDescription] className:className]);
[partialMockUtility stopMocking];
[partialMockLogger stopMocking];
}
In the above code, although [Utility isValidPropWithError:&error]; is called OCMVerify([partialMockUtility isValidPropWithError:&error]);is failing.
Several things here:
First, OCMVerify([partialMockUtility isValidPropWithError:&error] is failing because you are expecting the address of the NSError object you created in the test to be passed to isValidPropWithError:, but in MyClass +someMethod you are creating a different NSError object. The addresses of two different objects will not be the same.
To fix this, change your expectation and verification to:
OCMExpect([partialMockUtility isValidPropWithError:(NSError __autoreleasing**)[OCMArg anyPointer]]);
OCMVerify([partialMockUtility isValidPropWithError:(NSError __autoreleasing**)[OCMArg
and just ignore the actual value of the parameter and expect that it's going to be an NSError pointer (since you're creating it inside of someMethod, there's no way to know what it's going to be before you call the method).
Second, since you are already explicitly verifying +isValidPropWithError, OCMVerifyAll(partialMockUtility) isn't going to verify anything. You should either explicitly verify all of your expectations, or simply use OCMVerifyAll(partialMockUtility) and let it verify all your expectations and don't bother with expecting the specific call. OCMVerifyAll will verify everything you expect on the mock object you give it. This isn't going to cause a test failure - both calls will pass, since you've already verified the call the first time, the call to OCMVerifyAll() isn't going to have anything to verify, so it will pass.
Last, OCMVerify([partialMockLogger log:LoggerLevelWarning message:[error localizedDescription] className:className]); is failing because you didn't set an expectation for it.
- (void)testStringExample {
// Given
NSString *testString = #"Test";
id mock = OCMClassMock([NSString class]);
OCMStub([mock stringWithContentsOfFile:OCMOCK_ANY
encoding:NSUTF8StringEncoding
error:nil]).andReturn(testString);
// When
NSString *result = [NSString stringWithContentsOfFile:#"SomeFilePath"
encoding:NSUTF8StringEncoding
error:nil];
// Then
XCTAssertEqualObjects(result, testString);
}
As you can see I've been trying to stub an NSString class method using OCMock but don't seem to be having any luck. The test fails indicating that "(null)" is not equal to "Test" but I'm not sure why the mocked method isn't being called correctly. I'm using OCMock 3.1.2 on iOS. Any help greatly appreciated.
Having done a bit more reading, I suspect I've got a similar issue to that shown in the following post:
How to mock class method (+)?
I've subsequently adopted the approach suggested by Christopher Pickslay in the post above and it works a treat.
I'm trying to test the URL/path against a request is (or would be) made from a REST-client class using OCMock. The client uses RestKit (which uses AFNetworking) for the communication.
Therefore my plan was to:
Create a block which checks if a AFHTTPRequestOperation URL is the desired one.
Create a partial mock of the of AFHTTPClient.
Mock (stub) the enqueueHTTPRequestOperation: method with the block (of 1.).
Create a mock of RKObjectManager and set its HTTPClient property to the
AFHTTPClient partial-mock (of 2.).
Init an instance of my client-class with the mock-manager (from 4.).
Invoke the method of this instance of which the URL is to be checked.
Verify that enqueueHTTPRequestOperation: was invoked.
I'm not sure if I'm getting OCMock wrong because I couldn't find examples on mocking methods that take one or more arguments like I need to. ...never the less, this is how I tried to achieve the goal:
void (^checkBlock)(NSInvocation *) = ^(NSInvocation *invocation) {
AFHTTPRequestOperation *requestOperation = nil;
[invocation getArgument:&requestOperation atIndex:0];
XCTAssert(requestOperation != nil);
NSString *path = requestOperation.request.URL.path;
XCTAssert([path containsString:#"/rest/user/authenticate"]);
};
AFHTTPClient *httpClientMock = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:FAServerUrl]];
OCMPartialMock(httpClientMock);
[OCMStub([httpClientMock enqueueHTTPRequestOperation:[OCMArg isNotNil]]) andDo:checkBlock];
RKObjectManager *objectManager = OCMClassMock([RKObjectManager class]);
[OCMStub([objectManager HTTPClient]) andReturn:httpClientMock];
FAUserClient *userClient = [[FAUserClient alloc] initWithUser:nil objectManager:objectManager];
[userClient getAccessTokenForUsername:#"testuser"
password:#"pass123"
success:^(NSString *token, NSArray *roles) {
}
failure:^(NSInteger errorCode, NSError *error) {
}];
OCMVerify([httpClientMock enqueueHTTPRequestOperation:OCMOCK_ANY]);
But on [OCMStub([httpClientMock enqueueHTTPRequestOperation:[OCMArg isNotNil]]) andDo:checkBlock]; I get an EXC_BAD_ACCESS (code=1).
Apparently creating the mock-stub (with OCMStub) invokes the to be stubbed method, with the given [OCMArg isNotNil]. I thought A: the parameter just has a declarative meaning and B: this creates a stub and does not invoke the method right away.
Any help or suggestions leading into the "right" direction would be greatly appreciated.
EDIT:
As well tried:
OCMStub([httpClientMock enqueueHTTPRequestOperation:[OCMArg checkWithBlock:^BOOL(id obj) {
AFHTTPRequestOperation *request = (AFHTTPRequestOperation *)obj;
NSString *path = request.request.URL.path;
XCTAssert([path containsString:#"/rest/user/authenticate"]);
return YES;
}]]);
...with the same "result".
Best,
gabriel
Edit
Looked more closely. You are calling OCMPartialMock(httpClientMock). This does not convert the object you call it on, it returns a partial mock. Capture the result in a variable.
AFHTTPClient *httpClientMock = OCPartialMock([[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:FAServerUrl]]);
You should still make the change noted below in your andDo: block. You can also use the "modern" syntax for this:
OCMStub([myObject myMethod]).andDo(myBlock);
Original
I think the issue might be the code in the andDo: block.
[invocation getArgument:&requestOperation atIndex:0];
For all Objective-C methods, NSInvocation has two default arguments, self and _cmd at indexes 0 and 1. Try getting the argument at index 2.
You might also consider including NSInvocation+OCMAdditions which gives you getArgumentAtIndexAsObject . Another alternative is using [OCMArg checkWithBlock:] in which the arg is handed to your evaluation block directly.
H guys,
I have been trying for ages to find some good examples on how to use Kiwi testing to test delegate methods, asynchronously.
I have a manager class that defines the protocols for testing, with a pass and fail method returned in the delegate. Can anyone provide sample code on how to do this? Can I make the test class itself implement the to call the methods on the manager?
Thanks guys
You can do like in example
SPEC_BEGIN(IFStackOverflowRequestSpec)
describe(#"IFStackOverflowRequestSpec", ^
{
context(#"question request", ^
{
__block IFViewController *controller = nil;
beforeEach(^
{
controller = [IFViewController mock];
});
it(#"should conform StackOverflowRequestDelegate protocol", ^
{
[[controller should] conformToProtocol:#protocol(StackOverflowRequestDelegate)];
});
it(#"should recieve receivedJSON", ^
{
NSString *questionsUrlString = #"http://api.stackoverflow.com/1.1/search?tagged=iphone&pagesize=20";
IFStackOverflowRequest *request = [[IFStackOverflowRequest alloc] initWithDelegate:controller urlString:questionsUrlString];
[[request fetchQestions] start];
[[[controller shouldEventuallyBeforeTimingOutAfter(3)] receive] receivedJSON:any()];
});
it(#"should recieve fetchFailedWithError", ^
{
NSString *fakeUrl = #"asda";
IFStackOverflowRequest *request = [[IFStackOverflowRequest alloc] initWithDelegate:controller urlString:fakeUrl];
[[request fetchQestions] start];
[[[controller shouldEventuallyBeforeTimingOutAfter(1)] receive] fetchFailedWithError:any()];
});
});
});
Full example can be founded on this link.
You can do what I think you're trying to achieve by creating a mock object that stands in for the delegate, and then checking that the mock object receives the delegate callbacks that you expect. So the process would look like:
create a mock object that conforms to the delegate protocol:
id delegateMock = [KWMock mockForProtocol:#protocol(YourProtocol)];
set the mock as the delegate of your manager class:
[manager setDelegate:delegateMock];
create an object containing the data that will be returned by your manager class:
NSString *response = #"foo";
set the assertion that the mock should eventually be called with the method and response object (in this case, I'm expecting to receive managerRepliedWithResponse and foo)
[[[delegateMock shouldEventually] receive] managerRepliedWithResponse:response];
call the method under test:
[manager performMyMethod];
The key is setting the expectation before you call the method, and using shouldEventually which delays the assertion being checked and gives the manager object time to perform the method.
There's a range of expectations you can also use that are listed on the Kiwi wiki - https://github.com/allending/Kiwi/wiki/Expectations
I've written the process up in more detail in a post on my site, albeit that it's more specifically geared-up to the situation I was dealing with.
I am trying to test that a timer object is stopped after a level is completed.. I have the following code:
-(void)advanceLevel {
int nextLevelId = self.currentLevel.id + 1;
self.currentLevel = [[Level alloc] initWithIdentifier:nextLevelId];
[self.timer stop];
[self prepareLevel];
}
...
The prepareLevel method resets the timer value and calls "start" on it--- so in order to test that advanceLevel actually stops the timer, I need to overwrite the prepareLevel method.
So in my unit test, I did the following:
-(void)testItStopsTheTimer {
[timer start];
id mockGame = [OCMockObject partialMockForObject:game];
[[[mockGame stub] andReturn:nil] prepareLevel];
[game advanceLevel];
STAssertFalse(timer.active, nil);
}
Which results in XCode saying "testItStopsTheTimer (Gametests) failed. Ended up in subclass forwarder for Game-0x12383060......."
So, is it not possible to stub out an existing method and replace it with nothingness?
What you're trying to do is definitely possible with OCMock.
What is the method signature for prepareLevel? If it returns void, your mock setup should be:
[[mockGame stub] prepareLevel];
not:
[[[mockGame stub] andReturn:nil] prepareLevel];
What you are trying to do is possible with OCMock. In your test code one lines stands out:
id mockGame = [OCMockObject partialMockForObject:game];
The question is, where does "game" come from? Is the same instance used in multiple tests? The error you are seeing can be caused by the following sequence: you are using expect on a partial mock, the expected method is called, then you are called the method again, but now there's no expectation left and the partial mock doesn't know what to do.
UPDATE: I have just changed OCMock so that in such cases the mock simply forwards the method to the real object. See: https://github.com/erikdoe/ocmock/commit/e03d4fe74465b4fe3fa33552e036de8986f8dec2