blob: 4aadb77185848b28855eea57b1267e1d5960b94d [file] [log] [blame]
/*
* Copyright (c) 2013-2015 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
#import "OCClassMockObject.h"
#import "OCPartialMockObject.h"
#pragma mark Helper classes
@interface TestClassWithClassMethods : NSObject
+ (NSString *)foo;
+ (NSString *)bar;
- (NSString *)bar;
@end
@implementation TestClassWithClassMethods
static NSUInteger initializeCallCount = 0;
+ (void)initialize
{
initializeCallCount += 1;
}
+ (NSUInteger)initializeCallCount
{
return initializeCallCount;
}
+ (NSString *)foo
{
return @"Foo-ClassMethod";
}
+ (NSString *)bar
{
return @"Bar-ClassMethod";
}
- (NSString *)bar
{
return @"Bar";
}
@end
@interface TestSubclassWithClassMethods : TestClassWithClassMethods
@end
@implementation TestSubclassWithClassMethods
@end
@interface OCMockObjectClassMethodMockingTests : XCTestCase
@end
@implementation OCMockObjectClassMethodMockingTests
#pragma mark Tests stubbing class methods
- (void)testCanStubClassMethod
{
id mock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[[mock stub] classMethod] andReturn:@"mocked"] foo];
XCTAssertEqualObjects(@"mocked", [TestClassWithClassMethods foo], @"Should have stubbed class method.");
}
- (void)testCanExpectTheSameClassMethodMoreThanOnce
{
id mock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[[mock expect] classMethod] andReturn:@"mocked-foo"] foo];
[[[[mock expect] classMethod] andReturn:@"mocked-foo2"] foo];
XCTAssertEqualObjects(@"mocked-foo", [TestClassWithClassMethods foo], @"Should have stubbed class method 'foo'.");
XCTAssertEqualObjects(@"mocked-foo2", [TestClassWithClassMethods foo], @"Should have stubbed class method 'foo2'.");
}
- (void)testClassReceivesMethodsAfterStopWasCalled
{
id mock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[[mock stub] classMethod] andReturn:@"mocked"] foo];
[mock stopMocking];
XCTAssertEqualObjects(@"Foo-ClassMethod", [TestClassWithClassMethods foo], @"Should not have stubbed class method.");
}
- (void)testClassReceivesMethodAgainWhenExpectedCallOccurred
{
id mock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[[mock expect] classMethod] andReturn:@"mocked"] foo];
XCTAssertEqualObjects(@"mocked", [TestClassWithClassMethods foo], @"Should have stubbed method.");
XCTAssertEqualObjects(@"Foo-ClassMethod", [TestClassWithClassMethods foo], @"Should have 'unstubbed' method.");
}
- (void)testCanStubClassMethodFromMockForSubclass
{
id subclassMock = [OCMockObject mockForClass:[TestSubclassWithClassMethods class]];
[[[[subclassMock stub] classMethod] andReturn:@"mocked-subclass"] foo];
XCTAssertEqualObjects(@"mocked-subclass", [TestSubclassWithClassMethods foo], @"Should have stubbed method.");
XCTAssertEqualObjects(@"Foo-ClassMethod", [TestClassWithClassMethods foo], @"Should not have stubbed method in superclass.");
}
- (void)testSuperclassReceivesMethodsAfterStopWasCalled
{
id mock = [OCMockObject mockForClass:[TestSubclassWithClassMethods class]];
[[[[mock stub] classMethod] andReturn:@"mocked"] foo];
[mock stopMocking];
XCTAssertEqualObjects(@"Foo-ClassMethod", [TestSubclassWithClassMethods foo], @"Should not have stubbed class method.");
}
- (void)testCanReplaceSameMethodInSubclassAfterSuperclassMockWasStopped
{
id superclassMock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
id subclassMock = [OCMockObject mockForClass:[TestSubclassWithClassMethods class]];
[[[[superclassMock stub] classMethod] andReturn:@"mocked-superclass"] foo];
[superclassMock stopMocking];
[[[[subclassMock stub] classMethod] andReturn:@"mocked-subclass"] foo];
XCTAssertEqualObjects(@"mocked-subclass", [TestSubclassWithClassMethods foo], @"Should have stubbed method");
}
- (void)testCanReplaceSameMethodInSuperclassAfterSubclassMockWasStopped
{
id superclassMock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
id subclassMock = [OCMockObject mockForClass:[TestSubclassWithClassMethods class]];
[[[[subclassMock stub] classMethod] andReturn:@"mocked-subclass"] foo];
[subclassMock stopMocking];
[[[[superclassMock stub] classMethod] andReturn:@"mocked-superclass"] foo];
XCTAssertEqualObjects(@"mocked-superclass", [TestClassWithClassMethods foo], @"Should have stubbed method");
}
- (void)testStubbingIsOnlyActiveAtTheClassItWasAdded
{
// stage 1: stub in superclass affects only superclass
id superclassMock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[[superclassMock stub] classMethod] andReturn:@"mocked-superclass"] foo];
XCTAssertEqualObjects(@"mocked-superclass", [TestClassWithClassMethods foo], @"Should have stubbed method");
XCTAssertEqualObjects(@"Foo-ClassMethod", [TestSubclassWithClassMethods foo], @"Should NOT have stubbed method");
[superclassMock stopMocking];
// stage 2: stub in subclass affects only subclass
id subclassMock = [OCMockObject mockForClass:[TestSubclassWithClassMethods class]];
[[[[subclassMock stub] classMethod] andReturn:@"mocked-subclass"] foo];
XCTAssertEqualObjects(@"Foo-ClassMethod", [TestClassWithClassMethods foo], @"Should NOT have stubbed method");
XCTAssertEqualObjects(@"mocked-subclass", [TestSubclassWithClassMethods foo], @"Should have stubbed method");
[subclassMock stopMocking];
// stage 3: like stage 1; also demonstrates that subclass cleared all stubs
id superclassMock2 = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[[superclassMock2 stub] classMethod] andReturn:@"mocked-superclass"] foo];
XCTAssertEqualObjects(@"mocked-superclass", [TestClassWithClassMethods foo], @"Should have stubbed method");
XCTAssertEqualObjects(@"Foo-ClassMethod", [TestSubclassWithClassMethods foo], @"Should NOT have stubbed method");
}
- (void)testStubsOnlyClassMethodWhenInstanceMethodWithSameNameExists
{
id mock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[[mock stub] classMethod] andReturn:@"mocked"] bar];
XCTAssertEqualObjects(@"mocked", [TestClassWithClassMethods bar], @"Should have stubbed class method.");
XCTAssertThrows([mock bar], @"Should not have stubbed instance method.");
}
- (void)testStubsClassMethodWhenNoInstanceMethodExistsWithName
{
id mock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[mock stub] andReturn:@"mocked"] foo];
XCTAssertEqualObjects(@"mocked", [TestClassWithClassMethods foo], @"Should have stubbed class method.");
}
- (void)testStubsCanDistinguishInstanceAndClassMethods
{
id mock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[[mock stub] classMethod] andReturn:@"mocked-class"] bar];
[[[mock stub] andReturn:@"mocked-instance"] bar];
XCTAssertEqualObjects(@"mocked-class", [TestClassWithClassMethods bar], @"Should have stubbed class method.");
XCTAssertEqualObjects(@"mocked-instance", [mock bar], @"Should have stubbed instance method.");
}
- (void)testRevertsAllStubbedMethodsOnDealloc
{
id mock = [[OCClassMockObject alloc] initWithClass:[TestClassWithClassMethods class]];
[[[[mock stub] classMethod] andReturn:@"mocked-foo"] foo];
[[[[mock stub] classMethod] andReturn:@"mocked-bar"] bar];
XCTAssertEqualObjects(@"mocked-foo", [TestClassWithClassMethods foo], @"Should have stubbed class method 'foo'.");
XCTAssertEqualObjects(@"mocked-bar", [TestClassWithClassMethods bar], @"Should have stubbed class method 'bar'.");
mock = nil;
XCTAssertEqualObjects(@"Foo-ClassMethod", [TestClassWithClassMethods foo], @"Should have 'unstubbed' class method 'foo'.");
XCTAssertEqualObjects(@"Bar-ClassMethod", [TestClassWithClassMethods bar], @"Should have 'unstubbed' class method 'bar'.");
}
- (void)testRevertsAllStubbedMethodsOnPartialMockDealloc
{
id mock = [[OCPartialMockObject alloc] initWithClass:[TestClassWithClassMethods class]];
[[[[mock stub] classMethod] andReturn:@"mocked-foo"] foo];
[[[[mock stub] classMethod] andReturn:@"mocked-bar"] bar];
XCTAssertEqualObjects(@"mocked-foo", [TestClassWithClassMethods foo], @"Should have stubbed class method 'foo'.");
XCTAssertEqualObjects(@"mocked-bar", [TestClassWithClassMethods bar], @"Should have stubbed class method 'bar'.");
mock = nil;
XCTAssertEqualObjects(@"Foo-ClassMethod", [TestClassWithClassMethods foo], @"Should have 'unstubbed' class method 'foo'.");
XCTAssertEqualObjects(@"Bar-ClassMethod", [TestClassWithClassMethods bar], @"Should have 'unstubbed' class method 'bar'.");
}
- (void)testSecondClassMockDeactivatesFirst
{
id mock1 = [[OCClassMockObject alloc] initWithClass:[TestClassWithClassMethods class]];
[[[mock1 stub] andReturn:@"mocked-foo-1"] foo];
id mock2 = [[OCClassMockObject alloc] initWithClass:[TestClassWithClassMethods class]];
XCTAssertEqualObjects(@"Foo-ClassMethod", [TestClassWithClassMethods foo]);
[mock2 stopMocking];
XCTAssertNoThrow([TestClassWithClassMethods foo]);
}
- (void)testForwardToRealObject
{
NSString *classFooValue = [TestClassWithClassMethods foo];
NSString *classBarValue = [TestClassWithClassMethods bar];
id mock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[[mock expect] classMethod] andForwardToRealObject] foo];
NSString *result = [TestClassWithClassMethods foo];
XCTAssertEqualObjects(result, classFooValue);
XCTAssertNoThrow([mock verify]);
[[[mock expect] andForwardToRealObject] foo];
result = [TestClassWithClassMethods foo];
XCTAssertEqualObjects(result, classFooValue);
XCTAssertNoThrow([mock verify]);
[[[[mock expect] classMethod] andForwardToRealObject] bar];
result = [TestClassWithClassMethods bar];
XCTAssertEqualObjects(result, classBarValue);
XCTAssertNoThrow([mock verify]);
[[[[mock expect] classMethod] andForwardToRealObject] bar];
XCTAssertThrowsSpecificNamed([mock bar], NSException, NSInternalInconsistencyException, @"");
[[[mock expect] andForwardToRealObject] bar];
XCTAssertThrowsSpecificNamed([mock bar], NSException, NSInternalInconsistencyException, @"Did not get the exception saying andForwardToRealObject not supported");
[[[mock expect] andForwardToRealObject] foo];
XCTAssertThrows([mock foo]);
}
- (void)testRefusesToCreateClassMockForNilClass
{
XCTAssertThrows(OCMClassMock(nil));
}
- (void)testInitializeIsNotCalledOnMockedClass
{
NSUInteger countBefore = [TestClassWithClassMethods initializeCallCount];
id mock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[TestClassWithClassMethods foo];
[[mock verify] foo];
NSUInteger countAfter = [TestClassWithClassMethods initializeCallCount];
XCTAssertEqual(countBefore, countAfter, @"Creating a mock should not have resulted in call to +initialize");
}
- (void)testCanStubNSObjectClassMethodsIncludingAlloc
{
TestClassWithClassMethods *dummyObject = [[TestClassWithClassMethods alloc] init];
id mock = [OCMockObject mockForClass:[TestClassWithClassMethods class]];
[[[mock stub] andReturn:dummyObject] new];
id newObject = [TestClassWithClassMethods new];
XCTAssertEqualObjects(dummyObject, newObject, @"Should have stubbed +new method");
}
@end