Permalink
Browse files

Added support for partial mocks

  • Loading branch information...
1 parent 050f3dc commit a8ff0c28a94b61d71bd0e85cad0748b41767b231 @danielrhammond danielrhammond committed Mar 2, 2013
Showing with 60 additions and 0 deletions.
  1. +10 −0 Classes/KWMock.h
  2. +26 −0 Classes/KWMock.m
  3. +24 −0 Tests/KWMockTest.m
View
10 Classes/KWMock.h
@@ -15,8 +15,10 @@
@interface KWMock : NSObject {
@private
+ BOOL isPartialMock;
BOOL isNullMock;
NSString *mockName;
+ id mockedObject;
Class mockedClass;
Protocol *mockedProtocol;
NSMutableArray *stubs;
@@ -37,6 +39,9 @@
- (id)initAsNullMockWithName:(NSString *)aName forClass:(Class)aClass;
- (id)initAsNullMockWithName:(NSString *)aName forProtocol:(Protocol *)aProtocol;
+- (id)initAsPartialMockForObject:(id)object;
+- (id)initAsPartialMockWithName:(NSString *)aName forObject:(id)object;
+
+ (id)mockForClass:(Class)aClass;
+ (id)mockForProtocol:(Protocol *)aProtocol;
+ (id)mockWithName:(NSString *)aName forClass:(Class)aClass;
@@ -47,12 +52,17 @@
+ (id)nullMockWithName:(NSString *)aName forClass:(Class)aClass ;
+ (id)nullMockWithName:(NSString *)aName forProtocol:(Protocol *)aProtocol;
++ (id)partialMockForObject:(id)object;
++ (id)partialMockWithName:(NSString *)aName forObject:(id)object;
+
#pragma mark -
#pragma mark Properties
@property (nonatomic, readonly) BOOL isNullMock;
+@property (nonatomic, readonly) BOOL isPartialMock;
@property (nonatomic, readonly) NSString *mockName;
@property (nonatomic, readonly) Class mockedClass;
+@property (nonatomic, readonly) id mockedObject;
@property (nonatomic, readonly) Protocol *mockedProtocol;
#pragma mark -
View
26 Classes/KWMock.m
@@ -114,6 +114,18 @@ - (id)initAsNullMock:(BOOL)nullMockFlag withName:(NSString *)aName forClass:(Cla
return self;
}
+- (id)initAsPartialMockForObject:(id)object {
+ return [self initAsPartialMockWithName:nil forObject:object];
+}
+
+- (id)initAsPartialMockWithName:(NSString *)aName forObject:(id)object {
+ if ((self = [self initAsNullMock:YES withName:aName forClass:[object class] protocol:nil])) {
+ isPartialMock = YES;
+ mockedObject = [object retain];
+ }
+ return self;
+}
+
+ (id)mockForClass:(Class)aClass {
return [[[self alloc] initForClass:aClass] autorelease];
}
@@ -146,7 +158,16 @@ + (id)nullMockWithName:(NSString *)aName forProtocol:(Protocol *)aProtocol {
return [[[self alloc] initAsNullMockWithName:aName forProtocol:aProtocol] autorelease];
}
++ (id)partialMockWithName:(NSString *)aName forObject:(id)object {
+ return [[[self alloc] initAsPartialMockWithName:aName forObject:object] autorelease];
+}
+
++ (id)partialMockForObject:(id)object {
+ return [[[self alloc] initAsPartialMockForObject:object] autorelease];
+}
+
- (void)dealloc {
+ [mockedObject release];
[mockName release];
[stubs release];
[expectedMessagePatterns release];
@@ -157,8 +178,10 @@ - (void)dealloc {
#pragma mark -
#pragma mark Properties
+@synthesize isPartialMock;
@synthesize isNullMock;
@synthesize mockName;
+@synthesize mockedObject;
@synthesize mockedClass;
@synthesize mockedProtocol;
@synthesize stubs;
@@ -442,6 +465,9 @@ - (void)forwardInvocation:(NSInvocation *)anInvocation {
if ([self processReceivedInvocation:anInvocation])
return;
+ if (isPartialMock)
+ [anInvocation invokeWithTarget:self.mockedObject];
+
if (self.isNullMock)
return;
View
24 Tests/KWMockTest.m
@@ -42,6 +42,23 @@ - (void)testItShouldInitializeForAProtocolWithANameAsANullObject {
STAssertEqualObjects([mock mockName], @"JumpCapable mock", @"expected class mock to have the correct mockName");
}
+- (void)testItShouldInitializeAPartialMockForAClass {
+ id mockedObject = [[Cruiser alloc] init];
+ id name = @"Cruiser mock";
+ id mock = [KWMock partialMockWithName:name forObject:mockedObject];
+ STAssertNotNil(mock, @"expected a mock object to be initialized");
+ STAssertEqualObjects([mock mockedObject], mockedObject, @"expected the mockedClass property to be set");
+ STAssertTrue([mock isPartialMock], @"expected the isPartialMock property to be set");
+}
+
+- (void)testItShouldPassThroughAMessageToTheMockedObjectAsAPartialMock {
+ id callsign = @"Object Callsign";
+ id mockedObject = [[Cruiser alloc] initWithCallsign:callsign];
+ id mock = [KWMock partialMockForObject:mockedObject];
+ id returnedCallsign = [mock callsign];
+ STAssertEqualObjects(returnedCallsign, callsign, @"expected the partial mock to pass through a message to the object");
+}
+
//- (void)testItShouldRaiseWhenReceivingUnexpectedMessageAsAMock {
// id mock = [KWMock mockForClass:[Cruiser class]];
// STAssertThrows([mock objectAtIndex:0], @"expected mock to raise exception");
@@ -144,6 +161,13 @@ - (void)testItShouldStubWhitelistedMethods {
STAssertEqualObjects([mock copy], @"bacon", @"expected method to be stubbed");
}
+- (void)testItShouldStubWithAsAPartialMock {
+ id mockedObject = [[Cruiser alloc] initWithCallsign:@"asdf"];
+ id mock = [KWMock partialMockForObject:mockedObject];
+ [mock stub:@selector(callsign) andReturn:@"test callsign"];
+ STAssertEqualObjects([mock callsign], @"test callsign", @"expected the partial mock to hit a stub when defined");
+}
+
- (void)testItShouldNotRaiseForWhitelistedMethods {
id mock = [Cruiser mock];
STAssertNoThrow([mock isEqual:mock], @"expected no exception");

0 comments on commit a8ff0c2

Please sign in to comment.