OCMockのインストールは次を参照
何ができるのか(書き方)は次を参照
andReturnValueを使い、OCMOCK_VALUEでラップする
id blog = [OCMockObject mockForClass:[Blog class]];
[[[blog stub] andReturnValue:OCMOCK_VALUE((BOOL){NO})] isPublished];
もしくは
id blog = [OCMockObject mockForClass:[Blog class]];
BOOL flag = NO;
[[[blog stub] andReturnValue:OCMOCK_VALUE(flag)] isPublished];
[OCMArg any]
Blogクラスにfindとeditを用意し、edit実行時にfindが呼ばれているかどうかをチェック
※モックオブジェクトのverifyを呼ぶのを忘れないように
プロダクトコード
#import "Blog.h"
@implementation Blog
-(void)find:(int)no
{
}
-(void)edit:(int)no
{
[self find:no];
}
@end
テストコード
-(void)testEdit
{
id blog = [OCMockObject partialMockForObject:[[Blog alloc] init]];
[[blog expect] find:1]; // find:が引数1で呼ばれたかどうか?
[blog edit:1]; // テストしたいメソッドを実行
[blog verify]; // verifyで結果が検証される
}
設定したいスタブコード
[[[outputStream stub] andReturnValue:OCMOCK_VALUE((int){[sendData length]})] write:[OCMArg anyPointer] maxLength:[sendData length]];
実行するとwrite:[OCMArg anyPointer]の部分で次のエラーが出ます。
"Argument type '*' not supported."
そこで対象となるメソッドのSignatureを変更
@interface NSOutputStream (OCMockFix)
+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)selector;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector;
@end
@implementation NSOutputStream (OCMockFix)
+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)selector {
if (sel_isEqual(selector, @selector(write:maxLength:))) {
// Original signature is "i@:*I". Change '*' to '^C'
return [NSMethodSignature signatureWithObjCTypes:"i@:^CI"];
} else {
return [super instanceMethodSignatureForSelector:selector];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [[self class] instanceMethodSignatureForSelector:selector];
}
@end
これでスタブが設定できました。
subMessageが2回連続シリアル非同期で呼ばれることを確認したい。
1.subMessageが呼ばれるとフラグと回数を設定するコードを実行させる。(ブロックで渡す)
2.2回呼ばれるので2回expectを設定しておく。
3.フラグが設定されるまで先に進まないようにループを組んでおく。 (subMessageが呼ばれない場合に備え、念のため1秒でタイムアウトさせる)
テストしたいコード
- (void)testMessage
{
dispatch_queue_t testSerialDipatchQueue =
dispatch_queue_create("gcd.TestSerialDispatchQueue",DISPATCH_QUEUE_SERIAL);
dispatch_async(testSerialDipatchQueue, ^{
[self subMessage];
[self subMessage];
});
dispatch_release(testSerialDipatchQueue);
}
テストコード
id target = [OCMockObject mockForClass:[Target class]];
__block BOOL isSuccessed = NO;
__block int count = 0;
void (^theBlock)(NSInvocation *) = ^(NSInvocation *invocation) {
// subMessageが呼ばれたら設定
isSuccessed = YES;
count++;
};
[[[target expect] andDo:theBlock] subMessage];
[[[target expect] andDo:theBlock] subMessage];
[target testMessage];
NSDate *timeoutTime = [NSDate dateWithTimeIntervalSinceNow:1];
while (isSuccessed == NO) {
NSDate *currentTime = [NSDate date];
if ([currentTime compare:timeoutTime] == NSOrderedDescending) {
// 無限ループ回避(正常時は1秒以内にループを抜ける想定)
break;
}
}
STAssertTrue(count == 2, @"");