Skip to content

Commit

Permalink
Added support for partial mocks
Browse files Browse the repository at this point in the history
  • Loading branch information
danielrhammond committed Mar 9, 2013
1 parent 050f3dc commit a8ff0c2
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Classes/KWMock.h
Expand Up @@ -15,8 +15,10 @@

@interface KWMock : NSObject {
@private
BOOL isPartialMock;
BOOL isNullMock;
NSString *mockName;
id mockedObject;
Class mockedClass;
Protocol *mockedProtocol;
NSMutableArray *stubs;
Expand All @@ -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;
Expand All @@ -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 -
Expand Down
26 changes: 26 additions & 0 deletions Classes/KWMock.m
Expand Up @@ -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];
}
Expand Down Expand Up @@ -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];
Expand All @@ -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;
Expand Down Expand Up @@ -442,6 +465,9 @@ - (void)forwardInvocation:(NSInvocation *)anInvocation {
if ([self processReceivedInvocation:anInvocation])
return;

if (isPartialMock)
[anInvocation invokeWithTarget:self.mockedObject];

if (self.isNullMock)
return;

Expand Down
24 changes: 24 additions & 0 deletions Tests/KWMockTest.m
Expand Up @@ -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");
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit a8ff0c2

Please sign in to comment.