Check if argument is correct in OCMVerify - objective-c

In OCMock there is the method OCMVerify to verify interactions. So I did the following with MyObjectData being a simple value holder class.
OCMVerify([dataStore createOrUpdateMyObject:[OCMArg isKindOfClass:[MyObjectData class]]]);
This works, but is not enough, since I want to verify that the method isn't called with any object of this class but with the correct values. So I did the following:
// ...
OCMVerify([dataStore createOrUpdateMyObject:[OCMArg checkWithSelector:#selector(verifyMyObjectDataAfterSave:) onObject:self]]);
}
- (BOOL)verifyMyObjectDataAfterSave:(id)obj {
return YES;
}
But the obj parameter is not the MyObjectData instance I expect to be passed but an instance of OCMVerifier which is a proxy to the mocked data store.
Now the question is, how can I verify the argument correctly?

Can you use an expectation?
id mockObj = OCMPartialMock(dataStore);
OCMExpect([mockObj createOrUpdateMyObject:[OCMArg checkWithBlock:^BOOL(MyObjectData *value)
{
XCTAssertEqual(value.someProperty, 999);
return [value isKindOfClass:[MyObjectData class]];
}]]);
[mockObj someMethod];
OCMVerifyAll(mockObj);

Related

What is the analogue of Mockito.verifyZeroInteractions(obj) in the Mockk library?

I want to switch to Mockk, but i cant find analogue of this method in Mockk
It doesn't work
verify (exactly = 0) { obj }
The way you are trying it, is missing the method or variable
verify (exactly = 0) { obj.something }
Using the exactly zero approach would require
confirmVerified(obj)
To be sure nothing else was called.
The exact equivalent would be:
verify { obj wasNot Called }

State machine to handle sequential and async events

I created this state machine to handle events. I'm unsure about my implementation firstly because I don't use a transition table or anything like that, instead, I simply input the next event/state that needs to happen. I think this is cleaner than calling method to handle event b inside the method to handle event a, right?
Secondarily, since some of the methods have parameters - and this is not swift where enum members can have associated values, I added a param for that via withObj argument. I don't see a problem with this but want to know if this is confusing/violating something from your perspective.
I also found this useful for async task, so after the task completes I set resulting value to a local variable then update state to packData using that stored value amongst many other values already existing. This value is packed in a byte array which cannot be used in blocks so this was a useful workaround - although I haven't tested yet.
States are defined via enum like so:
typedef NS_ENUM(NSUInteger, ExampleState) {
ExampleStateIdle,
ExampleStateWaitingForAsyncTask,
ExampleStateReadyToPack,
ExampleStateRespond,
ExampleStateSomethingInProgress,
ExampleStateSomething2InProgress,
ExampleStateComplete
};
Here I define a method to handle each event using helper methods. I also have an extra argument for any state that might have an associated value.
- (void)updateState:(ExampleState)state withObj:(id)obj {
self.currentState = state;
switch (state) {
case ExampleStateWaitingForAsyncTask:
[self getAsyncInfo];
break;
case ExampleStateReadyToPack:
[self packData];
break;
case ExampleStateRespond:
[self respond:obj];
break;
case ExampleStateComplete:
[self showPopup];
break;
default:
break;
}
}
Example usage:
-(void)packData {
NSData *data = [NSData dataWithBytes:&result length:resultIndex];
// next step is to respond to `client`/`central` with data
[self updateState:ExampleStateRespond withObj:data];
}

OCMock: niceMockForClass expect zero call to method

In a test with OCMock, I must assert that no call is made to the setState: selector. However, I can make no assumption about the other calls that are made to the object.
Because any other call can be made, I have to (or do I?) use a niceMockForClass: instead of mockForClass:
How can I then make sure that no call is made to setState: ?
The code roughly looks like this:
- (void)testNoCallIsMadeToSetStateOnReset
{
self.downloader = [OCMock niceMockForClass:[Downloader class]];
[[self.downloader expectZero] setState:OCMOCK_ANY]; // <- how to do this?
// do some stuff
[self.downloader verify]
}
You can use [[yourMock reject] setState:OCMOCK_ANY];

Equivalent of times() in JMockIt?

I dont think minInvocation or maxInvocation is equivalent to times() in Mockito. Is there?
Please see this questions: Major difference between: Mockito and JMockIt
which has not been answered yet by anyone.
Edit
I found the answer myself: Adding it here for others who need this answered:
The solution is to use DynamicPartialMocking and pass the object to the constructor of the Expectations or NonStrictExpectations and not call any function on that object.
Then in the Verifications section, call any function on the object for which you want to measure the number of invocations and set times = the value you want
new NonStrictExpectations(Foo.class, Bar.class, zooObj)
{
{
// don't call zooObj.method1() here
// Otherwise it will get stubbed out
}
};
new Verifications()
{
{
zooObj.method1(); times = N;
}
};
I found the answer myself: Adding it here for others who need this answered:
The solution is to use DynamicPartialMocking and pass the object to the constructor of the Expectations or NonStrictExpectations and not call any function on that object.
Then in the Verifications section, call any function on the object for which you want to measure the number of invocations and set times = the value you want
new NonStrictExpectations(Foo.class, Bar.class, zooObj)
{
{
// don't call zooObj.method1() here
// Otherwise it will get stubbed out
}
};
new Verifications()
{
{
zooObj.method1(); times = N;
}
};

Overriding a setter method, and getting info out

I have a setter method (setMinimumNumberOfSides) that I want to override after using synthesize. In it, I'm putting in a constraint on the instance variable to make sure the int is within certain bounds.
Later in a custom init method, I'm setting another instance variable (numberOfSides), but I need to make sure minimumNumberOfSides and maximumNumberOfSides was set properly within bounds. I tried changing the return value on the setter to a BOOL, so I could pass back a YES or NO if it succeeded/failed, but that created a conflicting method, I'm guessing because I'm using synthesize and overriding the setter.
How can I get the info out easily to check to see if the setter was called and returned successfully?
-(void)setNumberOfSides:(int)sides
{
if ((sides < maximumNumberOfSides) && (sides > minimumNumberOfSides))
{
numberOfSides = sides;
}
else
NSLog (#"Invalid number of sides: %d is outside the constraints allowed", sides);
}
-(void)setMinimumNumberOfSides:(int)minimum
{
if (minimum > 2)
minimumNumberOfSides = minimum;
}
-(void)setMaximumNumberOfSides:(int)maximum
{
if (maximum <= 12)
maximumNumberOfSides = maximum;
}
-(id)initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max
{
if (self = [super init])
{
self.minimumNumberOfSides = min;
self.maximumNumberOfSides = max;
self.numberOfSides = sides;
}
return self;
}
You don't have to synthesize numberOfSides if you're planning on implementing the getter and setter. Without #synthesize numberOfSides you can return a BOOL if you choose. You'll need to declare the getter/setter in your interface accordingly.
BTW, another approach would be to use the synthesized getter/setter and add a separate method -(BOOL)isNumberOfSidesValid which performs this check.
In a situation like this, you may be better off using a simple call to assert(), or throwing an exception.
The choice will depend on how you see this class being used. If it will be part of a library, and you expect other developers to frequently supply incorrect values for minimumNumberOfSides or maximumNumberOfSides, you should probably throw a proper exception.
A word of warning, though. If you expect the users of your application to frequently supply incorrect values, then an exception is a bad idea. Exception handling in Objective-C is an expensive operation. If these checks are in place for the sake of the user, you should perform input validation, and report errors to the user in a much more friendly manner.
edit: Here is some quick sample code:
-(void)setMinimumNumberOfSides:(int)minimum
{
if (minimum <= 2)
{
[NSException raise:#"invalid minimumNumberOfSides value"
format:#"value of %d is too low (must be > 2)", minimum];
}
minimumNumberOfSides = minimum;
}
edit: Here is another SO question that goes into detail about exception handling in Objective-C.