LoginSignup
1
1

More than 5 years have passed since last update.

SVProgressHUDのモック化

Last updated at Posted at 2019-01-20

はじめに

UIのユニットテストを書く時の阻害要因になるのがSVProgressHUDの使用箇所(使っている場合)。こいつをなんとかモック化してみました。

問題

OCMockを使ってSVProgressHUDをモック化する場合、普通、以下の感じになります。


@implementation MockSVProgressHUD

+ (void)startMocking {

    mock = OCMClassMock([SVProgressHUD class]);

    [[[mock stub] andCall:@selector(showSuccessWithStatus:) onObject:self] showSuccessWithStatus:[OCMArg any]];
    [[[mock stub] andCall:@selector(showErrorWithStatus:) onObject:self] showErrorWithStatus:[OCMArg any]];
    [[[mock stub] andCall:@selector(dismiss) onObject:self] dismiss];

}

+ (void)showSuccessWithStatus:(nullable NSString*)status {
}

+ (void)showErrorWithStatus:(nullable NSString*)status {
}

+ (void)dismiss {
}

ところが、dismissメソッドはクラスメソッドとインスタンスメソッドの両方があり、その場合、SVProgressHUDのdismissメソッドが呼ばれます。さてさて

解決策

というわけで、SVProgressHUDのソースを読むと以下のようにシングルトンになっています。


+ (SVProgressHUD*)sharedView {
    static dispatch_once_t once;

    static SVProgressHUD *sharedView;
#if !defined(SV_APP_EXTENSIONS)
    dispatch_once(&once, ^{ sharedView = [[self alloc] initWithFrame:[[[UIApplication sharedApplication] delegate] window].bounds]; });
#else
    dispatch_once(&once, ^{ sharedView = [[self alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; });
#endif
    return sharedView;
}

以下のようにクラスメソッドからはそのシングルトンを直接、あるいは間接的に呼び出しています。


+ (void)setViewForExtension:(UIView*)view {
    [self sharedView].viewForExtension = view;
}

ということはそのsharedViewメソッドのreturn値をnilにすれば、とりあえずモックとして機能します。実装例を示します。


// プライベートメソッドを強引に開示する。
@interface SVProgressHUD(Testing)
+ (SVProgressHUD *)sharedView;
@end

@implementation MockSVProgressHUD

+ (void)startMocking {
    mock = OCMClassMock([SVProgressHUD class]);
    [[[mock stub] andCall:@selector(sharedView) onObject:self] sharedView];
}

...

// nilを返す事によってMock化する。
+ (SVProgressHUD *)sharedView {
    return nil;
}

無事、モック化できました。もっと挙動を制御したい時、テストスパイに仕立てたい時は、nilを返すのではなく、偽装するオブジェクトを返して各種インスタンスメソッドを実装する必要があるでしょう。

課題

  • OCMockを勉強すればもっとうまい方法があるかも。
  • SVProgressHUDの内部実装に依存する方法なので、将来バージョンアップして内部実装が変わった時にこの策は破綻するかも?。
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1