Testing void methods using OCMock in iOS - ios

I am trying to write a test case for a method in Objective-C class which returns void. The method mobileTest just creates another object of class AnotherClass and calls a method makeNoise. How to test this ?
I tried to use OCMock to create test this. Created a mock object of AnotherClass, and called mobileTest method. Obviously, the OCMVerify([mockObject makeNoise]) won't work, as I am not setting this object anywhere in the code. So, how to test in such cases ?
#interface Hello
#end
#implementation HelloWorldClass()
-(void)mobileTest{
AnotherClass *anotherClassObject = [AnotherClass alloc] init];
[anotherClassObject makeNoise];
}
#end
#interface AnotherClass
#end
#implementation AnotherClass()
-(void) makeNoise{
NSLog(#"Makes lot of noise");
}
#end
Test case for the above is as follows :
-(void)testMobileTest{
id mockObject = OCMClassMock([AnotherClass class]);
HelloWorldClass *helloWorldObject = [[HelloWorld alloc] init];
[helloWorldObject mobileTest];
OCMVerify([mockObject makeNoise]);
}

There's not a simple answer to this without going a bit into what OCMock is meant for and what test design paradigm it implies.
The short version is: You should not test this like that in the first place. Tests should treat the tested methods as a black box and only compare & verify input vs output.
Longer version: You're trying to test for a side effect, basically, since makeNoise doesn't do anything that the HelloWorldClass even registers (or "sees"). Or to put it in a more positive way: As long as makeNoise is properly tested in the tests written for AnotherClass you don't need to test that simple call.
The example you provide may be a bit confusing, since obviously that doesn't leave anything meaningful to test in mobileTest's unit test, but considering that you might also question why to outsource the simple NSLog call to another class in the first place (and testing for an NSLog call is kind of pointless, of course). Of course I understand you're just using this as an example and envision a more complex different scenario in which you want to ensure that a specific call happens.
In such a situation, you should always ask yourself "Is this the correct place to verify this?" If the answer is "yes" that should imply that whatever message you want to test to be called needs to go to an object that's not completely inside the scope of the tested class only. For example, it could be a singleton (some global logging class) or a property of the class. Then you have a handle, an object that you can properly mock (for example, set the property to a partially mocked object) and verify.
In rare cases that might lead you to provide a handle/property for an object simply to be able to replace it with a mock during testing, but that often indicates a sub-optimal class and/or method design (I'm not gonna claim that's always the case, though).
Let me provide three examples from one of my projects to illustrate something similar to your situation:
Example 1: Verifying that an URL is opened (in mobile Safari): This is basically verifying that openURL: is called on the shared NSApplication instance, something very similar to what you have in mind. Note that the shared instance is not "completely inside the tested methods scope" as it is a singleton"
id mockApp = OCMPartialMock([UIApplication sharedApplication]);
OCMExpect([mockApp openURL:[OCMArg any]]);
// call the method to test that should call openURL:
OCMVerify([mockApp openURL:[OCMArg any]]);
Note that this works due to the specifics of a partial mock: Even though openURL: is not called on the mock, because the mock has a relationship to same instance that is used in the tested method it can still verify the call. If the instance weren't a singleton that would not work, you would not be able to create the mock from the same object that is used in your method.
Example 2: Adapted version of your code to allow "grabbing" the internal object.
#interface HelloWorldClass
#property (nonatomic, strong) AnotherClass *lazyLoadedClass;
#end
#implementation HelloWorldClass()
// ...
// overridden getter
-(AnotherClass *)lazyLoadedClass {
if (!_lazyLoadedClass) {
_lazyLoadedClass = [[AnotherClass alloc] init];
}
return _lazyLoadedClass;
}
-(void)mobileTest{
[self.lazyLoadedClass makeNoise];
}
#end
And now the test:
-(void)testMobileTest{
HelloWorldClass *helloWorldObject = [[HelloWorld alloc] init];
id mockObject = OCMPartialMock([helloWorldObject lazyLoadedClass]);
OCMExpect([mockObject makeNoise]);
[helloWorldObject mobileTest];
OCMVerify([mockObject makeNoise]);
}
The lazyLoadedClass method might even be in a class extension, i.e. "private". In that case, just copy the according category definition to the top of your test file (I usually do this, and yes, this is, IMO, a valid case of basically "testing private methods"). This approach makes sense if AnotherClass is more complex and requires elaborate setup or something. Usually stuff like this then leads to the scenario you have in the first place, i.e. its complexity makes it to more than just a helper than can be thrown away after the method finishes. this will then also lead you to better code structure, since you have its initializer in a separate method and can test that accordingly, too.
Example 3: If AnotherClass has a non-standard initializer (like a singleton, or it comes from a factory class) you can stub that and return a mocked object (this is kind of a brain-knot, but I have used it)
#implementation AnotherClass()
// ...
-(AnotherClass *)crazyInitializer { // this is in addition to the normal one...
return [[AnotherClass alloc] init];
}
#end
-(void)testMobileTest{
HelloWorldClass *helloWorldObject = [[HelloWorld alloc] init];
id mockForStubbingClassMethod = OCMClassMock([AnotherClass class]);
AnotherClass *baseForPartialMock = [[AnotherClass alloc] init];
// maybe do something with it for test settup
id mockObject = OCMPartialMock(baseForPartialMock);
OCMStub([mockForStubbingClassMethod crazyInitializer]).andReturn(mockObject);
OCMExpect([mockObject makeNoise]);
[helloWorldObject mobileTest];
OCMVerify([mockObject makeNoise]);
}
This looks kind of stupid and I admit it's plain ugly, but I have used this in some tests (you know that point in a project...). Here I tried to make it easier to read and used two mocks, one to stub the class method (i.e. the initializer) and one that then is returned. The mobileTest method should then obviously use the custom initializer of AnotherClass, then it gets the mocked object (like a cuckoo's egg...). This is useful if you want to specially prepare the object (which is why I used a partial mock here). I am actually not sure atm if you could also do this with only one class mock (stub the class method/initializer on it so it returns itself, then expect the method call you want to verify)... as I said, brain-knotting.

Related

Objective-C dynamic implementation

Description + sample + explanation: (You can skip to the question section)
I'd like to make an object instance, which can be implemented by different implementations, depend on a condition (the internet status).
Simple declaration
#interface LoginController : NSObject
/** The currently logged-in User. Nil if not logged-in yet. */
#property (strong, nonatomic) User *currentUser;
// Singleton object
+ (instancetype)shareInstance;
/** Abstract methods, will do nothing if call directly. Use inheritance implements (Online/Offline) instead. */
- (User *)loginByEmail:(NSString *)email password:(NSString *)pwd;
#end
#interface LoginControllerOnline : LoginController
// Login will call request to server.
#end
#interface LoginControllerOffline : LoginController
// Login will check data in coredata.
#end
The LoginController's login method actually do nothing (return nil). Instead, the inherited class (Online/Offline) overwrite the parent login's method, with different implementations (as in comments)
And then, I have a manager to define which class should be in use:
#implement InternetManager
+ (LoginController *)loginController
{
return [self hasInternet] ? [LoginControllerOnline shareInstance] : [LoginControllerOffline shareInstance];
}
+ (BOOL)hasInternet
{
// Check with Reachability.
}
#end
This work. But it's not the mechanism I'd like to achieve.
This mean I have 2 instances of inherited LoginController instead of 1.
When internetStatus change from offline to online, I'd like to re-login online (to get session/oauthToken...). But, I'll have to do many things (copy user, change instance, check retained...) before I can actually call from login online
QUESTION:
Is there a way for me to create only one instance of LoginController, which hold the same properties (User), but can has different (dynamic) implementations (Online/Offline)?
Update question:
Quote from Apple's Dynamic typing:
The isa Pointer:
Every object has an isa instance variable that
identifies the object's class. The runtime uses this pointer to
determine the actual class of the object when it needs to.
So, is there a way for me to change this isa pointer of an object instance?
It sounds like the real problem is that you've given these things direct primary ownership of state that you actually don't want them to own — factor it out. There's no copying, just give each an instance of the thing that marshals sate at -init and allow them to talk to it.
Then just do the normal programming thing when you want to do either one thing or another based on a condition: use an if statement.
So, I don't think use of the dynamic runtime is appropriate. However, academically, supposing an interest:
If you really must, use object_setClass, which "[s]ets the class of an object", answering your actual question. Obviously you need the storage to be compatible, so probably your subclasses shouldn't declare any properties or instance variables.
A commonly-discussed alternative for this general area is not changing the class of an existing instance but changing the methods that are a member of the class. So you'd have two alternative implementations of -loginByEmail:password: and set which was the one that actually responded to that selector dynamically. But there's really no advantage over just using an if if you have access to the source code and a bunch of disadvantages around its generally indirect, opaque nature. The whole thing is usually known as swizzling. class_replaceMethod is the key component but just search for swizzling.

OCMock test category methods

I may not completely understand mocking as I have a burning question about a very basic scenario. How does one test an instance method of a class OR how does one test a category method for a class?
Consider a class PeerMessage which defines a few properties, etc. I create my own custom category for PeerMessage called Type where I define a method, isTextMessage:. isTextMessage returns a boolean value based on the contents of a PeerMessage. (Please not that this is just an sample type.)
In a test with OCMock, I configure a mock of type PeerMessage and set it's content to some valid value as follows:
id peerMessage = [OCMockObject mockForClass:[PeerMessage class]];
[[[peerMessage stub] andReturn:#"<valid>"] content];
And then assert that peerMessage is a text message:
XCTAssert([peerMessage isTextMessage]);
Considering how mocking works, this results in: 'Unexpected method invoked'. Clearly, as I didn't specify that I was expecting it; neither did I stub it. As I just wanted to verify this API.
How does one test these instance methods (in this case, category instance methods). One way to do this is to redesign the category as follows:
Instead of
- (BOOL)isTextMessage;
do:
+ (BOOL)isTextMessage:(PeerMessage *)message;
But this is to me is very unnatural and I don't feel like writing this code although I don't see anything wrong with it. It doesn't need to be class method. :/
(If my explanation for the question is a bit ambiguous, I'd be happy to update.)
You want to use a partial mock, somehow like this:
id peerMessage = [OCMockObject partialMockForObject:[[PeerMessage alloc] init]];
[[[peerMessage stub] andReturn:#"<valid>"] content];
XCTAssert([peerMessage isTextMessage]);
This way, the real implementation of isTextMessage, the one you want to test, is invoked, but you can still stub out other methods on the object.

Custom init from from NSClassFromString

I try to dynamically call certain viewController/Feature depends on his Name.NSClassFromString
(that kind of idea was suggested by Facebook).
For Instance from my server I can define in IOS app which feature or viewController should be used.(or On/Off them)
I searched all over Stack but still cant find an elegant way to implement what I want
Class myclass = NSClassFromString(className);
id obj = [[myclass alloc] init];
will work.
But I would like to call my custom init.
Class myclass = NSClassFromString(className);
id obj = [[myclass alloc] initWithCostumInitializer:userInfo];
I cant find a proper way to do it. Of course every time I receive an error because initWithCostumInitializer is not recognised.So I need to make the decision in run time.I believe I missing something.
Tnx a lot.
First off, you shouldn't get a compile-time error about an unknown method if the headers for the possible classe(s) are imported into the .m file where this code is running. Because of exactly this sort of dynamism, ObjC should let you get away with calling fairly arbitrary methods on objects of type id.
But that's just a bandaid solution. Really, if you know that that custom initializer method is present, then it's not an arbitrary class, right? You have some idea what kind of object it is, or at least what kind of base class it derives from, otherwise you wouldn't know to call that method. So you could always:
id customObj = [((BaseViewController *)[myclass alloc]) initWithCustumInitializer:userInfo];
If your error is a runtime error about the receiver missing that selector, then you have a real problem, which is: why are you calling a named method on an object that might not be the kind of object that has that method? If that's what's happening, you'll need to look at the class first to figure out what kind of thing you're actually about to create, and then behave appropriately for the init.

Forward selected class to use in another class

I'm having a bit of a brain fart. I hope someone can help me.
I have an app that communicates with different devices. Based on which device it's communicating with, I need to use different methods.
I have several different classes that do some parsing that I have made subclasses of a class called Parse (Don't confuse with the Parse cloud service), these only have Class methods. e.g. Parse_Device1 Parse_Device2
I have a third class (lets call it Selection) that returns all sorts of different stuff depending on what device the app is communicating with.
How can I have this class return the needed Parse subclass and use what's returned?
I know I could easily alloc and init the needed class, store it or return it.
However as all the methods on the parse classes are just Class methods, there's no need to init at all.
I've tried like this, however I don't seem to be able to use the returned class directly:
+ (Parser *)parser_AccessList
{
switch ([self brand]) {
case Brand1:
return [Parse_AccessList_1 alloc];
break;
case Brand2:
return [Parse_AccessList_2 alloc];
break;
case Brand3:
return [Parse_AccessList_3 alloc];
break;
default:
return nil;
break;
}
}
I'm probably missing something really simple here.
Thanks
This returns the class object. The caller may then instanciate on object of that very class or call class methods to it (by sending class method selectors).
return [Parse_AccessList_1 class];
Let's assume this is within the caller somewhere:
Class clazz = yourObject parser_AccessList];
[clazz performSelector:#selector(someMethod)];
As clazz is an object of type Class the related class method someMethod shoulc be called.
However, I am sure there are better ways of reaching your goal. Try using a delegation pattern and/or dependency inversion.
This method (message):
parser_AccessList
Is returning:
(Parser *)
That means that it will always return that allocated class type, so if you want to return "any" class you should define your method like this:
+ (id)parser_AccessList
The problem with this is that you don't know which class you should expect, so probably you are going to validate it after initialized.
Also, are you sure you don't need to initialize those parsers?
...
return [[Parse_AccessList_1 alloc] init];
...
In class methods "self" is the class itself. When allocating an instance ([Parse_AccessList_1 alloc]) you have to initialize!
EDIT:
#import <objc/runtime.h>
...
Class cl = NSClassFromString(#"TestClass");
return [[cl alloc] init];

OCMock test an object is allocated and a method is called on it

I'm finally imposing some TDD on a project I'm working on, and running into the edges... I know the code I want but not how to test for it :)
The implementation I'm looking for is:
- (void) doSomething
{
FooBuilder *foo = [[FooBuilder alloc] init];
[foo doSomethingElseWithCompletionBlock:^{
[self somethingDone];
}];
}
So I want my test to verify that a) the method under test allocates a new FooBuilder and b) that method then calls a method on the new object.
How do I go about this? I started down the path of trying to mock the alloc class method but quickly determined that down that path lies madness.
Note I'm not testing FooBuilder itself with this test, just that the collaboration is there.
Normally, dependency injection is used to provide a fully-formed object, saying "instead of asking for this object, here you go, use this." But in this case, we want the ability to instantiate a new object. So instead of injecting an object, all we have to do is inject the class. "Instead of creating a specific class, here you go, instantiate one of these."
There are two main forms of dependency injection: "constructor injection" (I'll stick with the term "constructor" even though Objective-C separates this into allocation and initialization) and "property injection".
For constructor injection, specify the class in the initializer:
- (instancetype)initWithFooBuilderClass:(Class)fooBuilderClass;
For property injection, specify the class in a property:
#property (nonatomic, strong) Class fooBuilderClass;
Constructor injection is clearer, because it makes the dependency obvious. But you may prefer property injection. Sometimes I start one way and refactor toward the other, changing my mind.
Either way, you can have a default initializer that either calls -initWithFooBuilderClass: , or sets the property, to [FooBuilderClass class].
Then doSomething would start like this:
- (void)doSomething
{
id foo = [[self.fooBuilderClass alloc] init];
...
I ended up addressing this by adding a new class method to FooBuilder which takes a completion block as an argument. So I've effectively moved the instantiation and method call out of my object-under-test into the collaborator object. Now I can mock that single class method call.
I think this ends up being slightly better design than what I started with; the detail that there needs to be a new FooBuilder instantiated is hidden from users of the class now. It's also pretty simple.
It does have the property that it maintains the strong coupling between my object-under-test and the FooBuilder class. Maybe that'll bite me down the road - but I'm making the YAGNI bet that it won't.

Resources