Skip to content

Instantly share code, notes, and snippets.

@andrewsardone
Created February 1, 2012 16:00
Show Gist options
  • Save andrewsardone/1717708 to your computer and use it in GitHub Desktop.
Save andrewsardone/1717708 to your computer and use it in GitHub Desktop.
Fake a neighboring class method for the object in test. Stolen from https://gist.github.com/1038034 with a clearer (to me) interface and example.
#import <SenTestingKit/SenTestingKit.h>
#import "SenTestCase+MethodSwizzling.h"
#pragma mark Fakes for Tests
@interface FakeMyObject : NSObject
/**
* A fake, or "stub," implementation of MyObject's +doSomething method.
*/
- (id)fakeDoSomething
@end
@implementation FakeMyObject
- (id)fakeDoSomething
{
NSLog(@"%s", __PRETTY_FUNCTION__);
id someFakeReturnObj = [[NSObject alloc] init];
return someFakeReturnObj;
}
@end
#pragma mark Tests
@interface ExampleTests : SenTestCase
@end
@implementation ExampleTests
- (void)testSomeBehavior
{
[self swizzleClassMethod:@selector(doSomething)
inClass:[MyObject class]
withClassMethod:@selector(fakeDoSomething)
fromClass:[FakeMyObject class]
executeBlock:^
{
id objectInTest = [[Foo alloc] init];
[objectInTest someBehavior]; // some action that uses MyObject's
// doSomething class method
STAssertTrue(objectInText.someState,
@"someState should be true due to someBehavior");
}
];
}
@end
#import <SenTestingKit/SenTestingKit.h>
/**
* Category on top of SenTestCase to provide convenience methods for changing
* the implementation of some selector (i.e., stubbing) for execution of a block
* where test assertions can be made.
*
* Cribbed from https://gist.github.com/1038034
*/
@interface SenTestCase (MethodSwizzling)
/**
* Changes the implementation of some class method for the execution of a block.
*
* @param aOriginalMethod
* The selector of the original method that needs to be faked.
* @param aOriginalClass
* The class containing the original method that needs to be faked.
* @param aNewMethod
* The selector for the fake implementation that will be used within
* the test.
* @param aNewClas
* The class containing the fake implementation that will be used
* within the test.
* @param aBlock
* The block that executes within the context of the fake
* implementation.
*/
- (void)swizzleClassMethod:(SEL)aOriginalMethod
inClass:(Class)aOriginalClass
withClassMethod:(SEL)aNewMethod
fromClass:(Class)aNewClass
executeBlock:(void (^)(void))aBlock;
@end
#import "SenTestCase+MethodSwizzling.h"
#include <objc/runtime.h>
@implementation SenTestCase (MethodSwizzling)
- (void)swizzleClassMethod:(SEL)aOriginalMethod
inClass:(Class)aOriginalClass
withClassMethod:(SEL)aNewMethod
fromClass:(Class)aNewClass
executeBlock:(void (^)(void))aBlock
{
Method originalMethod = class_getClassMethod(aOriginalClass, aOriginalMethod);
Method mockMethod = class_getClassMethod(aNewClass, aNewMethod);
method_exchangeImplementations(originalMethod, mockMethod);
aBlock();
method_exchangeImplementations(mockMethod, originalMethod);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment