LoginSignup
2
2

More than 5 years have passed since last update.

[objective-c][unit test] class method をmockする

Last updated at Posted at 2013-12-18

概要

Unit test書いてる時、util classとか結構使うので、そして問題。 class methodをどうやってmockするの???
Kiwiインスタンスに対してしかmockできないため、別の方法考えないと行けない。

自分が思いついた簡単なやり方

そのclass methodを使うところを一つのmethodにラップし、test projectの方にテストしたいclassのcategroyを作って、そのmethodを上書きすればいい。

サンプル

例えばIn app purchaseアイテム購入する前にネットワーク繋いでるかの検証が必要で、ネットワークが繋いでないときのテストが書きたい。

MyTarget

InAppPurchaseManager.h
- (void)purchaseProductWithProduct:(SKProduct *)product success:(void (^)(SKPaymentTransaction *transaction))success failure:(void (^)(NSError *error))failure {
     //ネットワークonline判定
    if(![self p_isNetworkOnline]){
        failure([NetworkError networkOfflineError]);
        return;
    }
    _purchaseSuccess = success;
    _purchaseFailure = failure;

   // item購入
    SKPayment *payment = [SKPayment paymentWithProduct:product];
    [_paymentQueue addPayment:payment];
}

// ネットワーク検証をprivate methodに
-(BOOL)p_isNetworkOnline{
    return [NetworkUtil networkOnline];
}

MyTestTarget

InAppPurchaseManagerクラスのcategory作成

InAppPurchaseManager+Injection.h
//mock networkStatus設定
- (void)setNetworkStatus:(BOOL)status;
InAppPurchaseManager+Injection.m
- (void)setNetworkStatus:(BOOL)status {
  // category内にインスタンス変数使えないため
    objc_setAssociatedObject(self, @"networkStatus",[NSNumber numberWithBool:status],OBJC_ASSOCIATION_ASSIGN);
}

//private methodを上書き
-(BOOL)p_isNetworkOnline{
    id status = objc_getAssociatedObject(self, @"networkStatus");
    return [status boolValue];
}

テストコード:

InAppPurchaseManagerSpec.m
context(@"when device offline", ^{
                beforeEach(^{
                    // offlineの状態を設定
                    [_inAppPurchaseManager setNetworkStatus:NO];
                    [_inAppPurchaseManager purchaseProductWithProduct:_validProduct success:emptySuccessBlock failure:emptyFailureBlock];
                });
                it(@"should never call success block", ^{
                    [[theValue(_successCalled) should] equal:theValue(NO)];
                });

                it(@"should call failure block", ^{
                    [[theValue(_failureCalled) should] equal:theValue(YES)];
                });
                it(@"should return offline error", ^{
                    [[_error shouldNot] beNil];
                    [[expectFutureValue(_error.domain) should] equal:NetworkErrorDomain];
                    [[expectFutureValue(theValue(_error.code)) should] equal:theValue(NetworkErrorOffline)];
                });
            });

注:テストフレームワークはkiwiを使ってます

h2 追記

OCMock class methodのmockはサポートしているらしい。検証次第追記します

2
2
3

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
2
2