Testing Class Methods with OCMock - ios

Based on the documentation of OCMock, it should be possible to test class methods, but I may be misunderstanding what is and isn't possible with OCMock. Take the following example method I wish to test:
- (void)methodToTest {
[SVProgressHUD dismiss];
}
I'd like to test that dismiss is called on SVProgressHUD. I currently use the following test, but that doesn't seem to do the trick.
- (void)testMethodToTest {
// Create Mock Progress HUD
id mockProgressHUD = OCMClassMock([SVProgressHUD class]);
// Configure Mock Progress HUD
OCMStub(ClassMethod([mockProgressHUD dismiss]));
// Invoke Method to Test
[object methodToTest];
OCMVerify([mockProgressHUD dismiss]);
}
Is it possible with OCMock to test whether dismiss is called on SVProgressHUD?

Your test passes for me. Perhaps it's something subtle in your implementation? What is object? Here's my simplified version:
#interface Foo : NSObject
+ (void)dismiss;
#end
#implementation Foo
+ (void)dismiss
{
NSLog(#"Dismiss!");
}
#end
#interface Bar : NSObject
- (void)methodToTest;
#end
#implementation Bar
- (void)methodToTest
{
[Foo dismiss];
}
#end
- (void)testClassMock
{
Bar *bar = [Bar new];
id mockFoo = OCMClassMock([Foo class]);
OCMStub(ClassMethod([mockFoo dismiss]));
[bar methodToTest];
OCMVerify([mockFoo dismiss]);
}

Related

Strange retain cycle warning in unit tests in Xcode

I have a service that I'm currently writing a unit test for. The code works as expected, but I'm getting a strange retain cycle warning.
[self.myService doSomethingCoolWithCompletionBlock:^(MyResponseObject *obj) {
XCTAssertNil(obj, #"obj should be nil");
}];
The XCTAssertNil(obj, #"obj should be nil"); line shows a warning in Xcode Capturing 'self' strongly in this block is likely to lead to a retain cycle.
If I change the code to the following, the warning is removed:
__weak MyService *weakService = self.myService;
[weakService doSomethingCoolWithCompletionBlock:^(MyResponseObject *obj) {
XCTAssertNil(obj, #"obj should be nil");
}];
I am using self.someService in other unit tests, and never had this issue. Anyone experienced this before?
EDIT
I have another test that has the following:
[self.myService doSomethingElseCoolWithCompletionBlock:(NSArray *results) {
XCTestAssertNotNil(results, #"results should not be nil");
}];
This doesn't give me a warning. The only difference I see is that this is checking an array, and the other is checking an object of a specific type.
assert it is macros and used self inside.
so you need create local variable with name self.
__weak id weakSelf = self;
self.fooBlock = ^{
id self = weakSelf;
XCTAssert(YES);
};
Don't do this:
#interface MyCoolTests : XCTestCase
#property (retain) id myService;
#end
#implementation MyCoolTests
-(void)testCoolness{
self.myService = [MyService new];
self.myService.callback = ^{
XCTAssert(YES);
};
// ...
}
#end
Do this:
#interface MyCoolTests : XCTestCase
#end
#implementation MyCoolTests
-(void)testCoolness{
id myService = [MyService new];
myService.callback = ^{
XCTAssert(YES);
};
// ...
}
#end
It's a limitation of XCTTestCase and it probably catches people when using the setup method.

Singleton UIViewController

I'm trying to add some data from a random class to my viewController,
So to keep always the same data, i did a singleton on my UIViewController, but it doesnt work i never get the data on my tableview.
this what i added to my UIViewController :
+(id)sharedMBVC {
static MBViewController *sharedMBVC ;
#synchronized(self) {
if (!sharedMBVC)
sharedMBVC = [[MBViewController alloc] init];
return sharedMBVC;
}
}
and from my class i call it by doing this :
MBViewController *vc = [MBViewController sharedMBVC];
Do i have to set somewhere the content of my NSArrays that they are declared in my viewDidLoad of the viewcontroller ? or there is something else to do.
PS : i was doing in my class before vc = (MBViewController *)[[[[UIApplication sharedApplication] delegate] window] rootViewController]; but now my uiviewcontroller its not a rootview anymore, thats why im trying to find other way to access to it, and i guess the best solution is to do a singleton
Can u help me guys
OK, so the problem you have is that the viewController that displays the arrays also "owns" the arrays. This means that (with your current setup) to be able to change the arrays you need to get hold of the viewController to be able to access the arrays.
You need to change this by removing the arrays from that viewController.
You can still do this with a singleton (if you prefer) but create a brand new class called something like ArrayManager.
This will contain the arrays and ALL the methods for updating the arrays.
So for instance if your viewController has a method called - (void)addObjectToArray:(id)object; then move this method to the ArrayManager singleton class.
Now in your displaying viewController you can do...
[[ArrayManager sharedInstance] getSomeDataFromTheArray];
And in the place that has to update the array you can do...
[[ArrayManager sharedInstance] addObjectToArray:someObject];
Now you don't need to worry about passing the viewController around at all.
This can be improved with various things. For instance, you maybe don't need a singleton at all and can just take this ArrayManager class and inject it into the places that need it by setting a property etc...
Also, you could possibly use CoreData to store the information.
Also, your singleton method is not correct. The way recommended by Apple is to use...
+ (ArrayManager *)sharedInstance
{
static dispatch_once_t once;
static ArrayManager *arrayManager;
dispatch_once(&once, ^{
arrayManager = [[ArrayManager alloc] init];
});
return arrayManager;
}
Rewriting your singleton...
.h file
#interface PTVData : NSObject
+ (PTVData *)sharedInstance;
- (void)addSensor:(NSString *)sensorName;
- (NSInteger)numberOfSensors;
- (NSString *)sensorAtIndex:(NSUInteger)index;
#end
.m file
#interface PTVData ()
#property (nonatomic, strong) NSMutableArray *sensors;
#end
#implementation PTVData
+ (PTVData)sharedInstance
{
static PTVData *sharedPTVData;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPTVData = [[PTVData alloc] init];
});
return sharedPTVData;
}
- (id)init
{
if (self = [super init]) {
_sensors = [[NSMutableArray alloc] initWithObject:#"None"];
}
return self;
}
- (void)addSensor:(NSString *)sensorName
{
if (sensorName
&& ![self.sensors containsObject:sensorName]) {
[self.sensors addObject:sensorName];
}
}
- (NSInteger)numberOfSensors
{
return self.sensors.count;
}
- (NSString *)sensorAtIndex:(NSUInteger)index
{
return self.sensors[index];
}
#end
By doing this you hide the actual array of sensors. It is only directly accessible through the PTVData class.
Now in your tableview methods you can do...
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[PTVData sharedInstance] numberOfSensors];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = ...
cell.textLabel.text = [[PTVData sharedInstance] sensorAtIndex:indexPath.row];
return cell;
}
Well, I think, these arrays don't belong to the MBViewController from architectural point of view. I would separate them to a data layer (DataSource class of some sort, for instance) and keep a reference to the DataSource everywhere you need. Have a look at the Second iOS App tutorial by Apple. It contains a simple example of data layer implementation.
UPDATE:
Also, check out Fogmeister's answer. He explains a possible implementation of such object rather well :)
As for why singleton didn't work as you expected in this case, I believe, the reason could be the following:
If you get to the MBViewController via a segue (which, I think, you are), then a new instance of MBViewController is created every time. If you access your arrays from MBViewController using self.myArray, then you access this new MBViewController's myArray. While sharedMBVC keeps a reference to the shared instance, it's just ignored by the segue.
in my ViewController.h
#property PTVData *ptvdata;
ViewController.m
ViewDidload
ptvdata = [PTVData sharedPTVData];
_sensorsCollection = ptvdata.sensorsCollection;
then i have a method in my ViewController.m
- (void) addSensorToCollection:( NSString *)sensorName{
[[PTVData sharedPTVData] addSensorToCollection:sensorName];
_sensorsCollection = ptvdata.sensorsCollection;
[ self.tableView reloadData];
}
}
My PTVData.h
#property (nonatomic,retain) NSMutableArray *sensorsCollection;
+(id)sharedPTVData;
-(id) init;
- (void) addSensorToCollection:( NSString *)sensorName;
#end
my PTVData.m
#synthesize sensorsCollection = _sensorsCollection;
+ (id)sharedPTVData {
static PTVData *sharedPTVData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPTVData = [[self alloc] init];
});
return sharedPTVData;
}
- (id)init {
if (self = [super init]) {
_sensorsCollection = [[NSMutableArray alloc]initWithObjects:#"None", nil];
}
return self;
}
- (void) addSensorToCollection:( NSString *)sensorName{
if (![_sensorsCollection containsObject:sensorName]&& sensorName!= nil) {
[_sensorsCollection addObject:sensorName];
}
}
Instead of initializing your arrays in viewDidLoad, do it in sharedMBVC function. This will ensure that arrays are not re-initialized every time the view loads.

Compilation error with OCMockito verify and NSError**

I can not compile this code:
[verify(mockedContext) deleteObject:item1];
[verify(mockedContext) deleteObject:item2];
[verify(mockedContext) save:anything()];<--compilation error for conversion id to NSError**
However I'm able to pass compilation in similar case with given macros with additional syntax:
[[given([mockedContext save:nil]) withMatcher:anything()] willReturn:nil];
Are there anything to help me pass compilation with verify?
Here is compilation error:
Implicit conversion of an Objective-C pointer to 'NSError *__autoreleasing *' is disallowed with ARC
I assume the save: method on the 'mockedContext' takes a pointer-to-pointer to NSError.
So actually, the NSError must be seen as an extra return value of the save:method. This means that you should rather setup an expectation in the first place.
I worked out a small example:
We start with the Context protocol with a simple method taking an NSError**.
#protocol Context <NSObject>
- (id)doWithError:(NSError *__autoreleasing *)err;
#end
Next is a class using this protocol, much like your SUT. I called it ContextUsingClass
#interface ContextUsingClass : NSObject
#property (nonatomic, strong) id<Context> context;
#property BOOL recordedError;
- (void)call;
#end
#implementation ContextUsingClass
- (void)call {
NSError *error;
[self.context doWithError:&error];
if (error) {
self.recordedError = YES;
}
}
#end
As you can see, when the context method doWithError: returns an error, the recordedError property is set to YES. This is something we can expect to be true or false in our test. The only problem is, how do we tell the mock to result in an error (or to succeed without error)?
The answer is fairly straight forward, and was almost part of your question: we pass an OCHamcrest matcher to the given statement, which in turn will set the error for us through a block. Bear with me, we'll get there. Let's first write the fitting matcher:
typedef void(^ErrorSettingBlock)(NSError **item);
#interface ErrorSettingBlockMatcher : HCBaseMatcher
#property (nonatomic, strong) ErrorSettingBlock errorSettingBlock;
#end
#implementation ErrorSettingBlockMatcher
- (BOOL)matches:(id)item {
if (self.errorSettingBlock) {
self.errorSettingBlock((NSError * __autoreleasing *)[item pointerValue]);
}
return YES;
}
#end
This matcher will call the errorSettingBlock if it has been set, and will always return YES as it accepts all items. The matchers sole purpose is to set the error, when the test asks as much. From OCMockito issue 22 and it's fix, we learn that pointer-to-pointers are wrapped in NSValue objects, so we should unwrap it, and cast it to our well known NSError **
Now finally, here is how the test looks:
#implementation StackOverFlowAnswersTests {
id<Context> context;
ContextUsingClass *sut;
ErrorSettingBlockMatcher *matcher;
}
- (void)setUp {
[super setUp];
context = mockProtocol(#protocol(Context));
sut = [[ContextUsingClass alloc] init];
sut.context = context;
matcher = [[ErrorSettingBlockMatcher alloc] init];
}
- (void)testContextResultsInError {
matcher.errorSettingBlock = ^(NSError **error) {
*error = [NSError errorWithDomain:#"dom" code:-100 userInfo:#{}];
};
[[given([context doWithError:nil]) withMatcher:matcher] willReturn:nil];
[sut call];
assertThatBool(sut.recordedError, is(equalToBool(YES)));
}
- (void)testContextResultsInSuccess {
[[given([context doWithError:nil]) withMatcher:matcher] willReturn:nil];
[sut call];
assertThatBool(sut.recordedError, is(equalToBool(NO)));
}
#end
Conclusion
When you call methods within your SUT which are returning errors through pointer-to-pointers, you should probably test for the different possible outcomes, rather than just verifying if the method has been called.
If your SUT is ignoring the error, then let the block you pass into the matcher keep a boolean flag to indicate that it was called like so:
- (void)testNotCaringAboutTheError {
__block BOOL called = NO;
matcher.errorSettingBlock = ^(NSError **error) {
called = YES;
};
[[given([context doWithError:nil]) withMatcher:matcher] willReturn:nil];
[sut call];
assertThatBool(called, is(equalToBool(YES)));
}
Or with simple verification:
- (void)testWithVerifyOnly {
[sut call];
[[verify(context) withMatcher:matcher] doWithError:nil];
}
PS: Ignoring errors is probably something you don't want to do...

How to make settings inheritance

In my XCode project, I want some default setup settings, which basically is a set of variables like GlobalTintColor, ServerUrl and so forth.
I then need to override some of these settings per client/target.
These settings are only for interval use, which means I'm not looking for settings bundle type solution.
I don't want to have duplicate settings, so some sort of inheritance seems to be the right way to go.
I was thinking I'd make a parent class carrying all the default settings, and then a subclass for each client, overriding settings as needed. I just can't figure out how I'm going to load these settings. I figured only the clients that needed to override settings had a subclass. Other clients just used the default settings as defined by the parent class.
But when I'm loading the settings at application start, I then need to check if the subclass is available, and if not, I only load the super class.
But then I get the problem of what kind of class the settings are: subclass or superclass?
I've been looking into categories as well as class clustering, but haven't found a solution so far.
Seems to me this is functionality a lot of app developers need. Does any of you know of a good pattern to solve this?
To illustrate:
- (id) getAppConfigurationSettings {
id settings;
if ([AppConfigurationSettings class]) {
settings = [AppConfigurationSettings class];
} else {
settings = [DefaultAppConfigurationSettings class];
}
return settings;
}
Do you want something like this ?
"Parent.h"
#interface Parent : NSObject
#property(nonatomic,strong)UIColor *color;
#end
"Parent.m"
#import "Parent.h"
#implementation Parent
-(void)setColor:(UIColor *)color{
self.color=color;
}
#end
Then you create another class which will inherit Parent say Child
Child.h
#import "Parent.h"
#interface Child : Parent
#end
Child.m
#import "Child.h"
#implementation Child
//Override the actual color
-(void)setColor:(UIColor *)color{
self.color=color;
}
#end
Then you can use it like below
Parent *parent=[[Parent alloc] init];
[parent setColor:[UIColor redColor]];
Child *child=[[Child alloc] init];
[Child setColor:[UIColor blueColor]];
I hope it will give you enough idea..
Updated
For custom initialization you can create some enum, and do your initializations accordingly like below
typedef enum {
kParent = 1,
kChild = 2
}kSettings;
-(void)updateColor:(kSettings)settingType{
id classObj;
switch (settingType) {
case kParent:
classObj=[[Parent alloc] init];
break;
case kChild:
classObj=[[Child alloc] init];
break;
default:
break;
}
[classObj setColor:[UIColor redColor]];
}
Note - The above code is not tested may not be completely correct, but can be like this.
When I hear about "base" and "override", I immediately think of a hierarchy of classes, so #iphonic answer does the job pretty well, although I would design it in a slightly different way:
"BaseSettings"
#interface BaseSettings : NSObject
... properties
#end
#implementation BaseSettings
- (instancetype) init {
self = [super init];
if (self) {
[self constantInit];
[self dynamicInit];
}
}
// Put here initialization that won't be overridden
// in inherited classes
- (void) constantInit {
}
// Put here initialization that will be overridden
// in inherited classes
- (void) dynamicInit {
}
#end
"SettingsInheritor"
#interface SettingsInheritor : BaseSettings
#end
#implementation SettingsInheritor
- (void) dynamicInit {
// Call base method so that not overriden settings
// are still initialized properly
[super dynamicInit];
// Override settings here
...
}
The constantInit method is for convenience only, to let you visually separate constant from overrideable settings - so you can get rid of it if you won't need or like it.
What can be improved in #iphonic's answer is how the actual settings class is instantiated, so I propose a different approach.
As described here, you can use obj_getClassList() to obtain the list of all registered class definitions - then you can loop through all of them, and check if its superclass is BaseSettings (or whatever you want to call the base settings class), using class_getSuperClass() or isSubclassOfClass:. Note: the latter method returns YES if subclass or identical, something to take into account when comparing.
Once you find a class inheriting from BaseSettings, you can break the loop and instantiate the found class (for instance using class_createInstance()). A (untested) skeleton is like this:
int numClasses = objc_getClassList(NULL, 0);
if (numClasses > 0) {
BOOL found = NO;
Class settingsClass;
Class *classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
for (int index = 0; index < numClasses; ++index) {
Class curClass = classes[index];
Class superClass = class_getSuperclass(curClass);
const char *superClassName = class_getName(superClass);
if (strcmp(superClassName, "BaseSettings") == 0) {
settingsClass = curClass;
found = YES;
break;
}
}
if (found) {
// Create the class instance from `settingsClass`
}
free(classes);
}
Credits to Ole Begemann for (most of) the above code

iOS OCMock partial vs class mock

I am learning OCMock for iOS testing. What's the difference between "class mock" and "partial mock", and when should you use one vs the other?
http://ocmock.org/features/
Class mocks create objects that are pure mocks of a class instance.
Partial mocks take an instance of a class an allow you to stub any of its methods.
Suppose I have these classes:
#interface Foo : NSObject
- (void)doX;
#end
#implementation
- (void)doX
{
NSLog(#"X");
}
#end
#interface Bar : NSObject
- (void)doA:(Foo *)foo;
- (void)doB;
#end
#implementation Bar
- (void)doA:(Foo *)foo
{
NSLog(#"A");
[foo doX];
[self doB];
}
- (void)doB
{
NSLog(#"B");
}
#end
I'm interested in testing Bar's doA: method. I expect it to call doX on a Foo object, then to call its own doB method. I would implement this using a class mock of a Foo and a partial mock of a Bar.
- (void)test_doA_shouldCall_doX_and_doB
{
id objectUnderTest = [OCMockObject partialMockForObject:[Bar new]];
id fooMock = [OCMockObject mockForClass:Foo.class];
[[fooMock expect] doX];
[[objectUnderTest expect] doB];
// Make the call
[objectUnderTest doA:fooMock];
[objectUnderTest verify];
[fooMock verify];
}
You see here that my partial mock allowed me to call the real method I wanted to test while mocking an internal call to another of its instance methods. Because I didn't need any of the real functionality of Foo, however, I used a class mock.

Resources