2011-12-08 107 views
4

需要爲以下代碼編寫單元測試,我想爲類方法canMakePayments做模擬,返回yes或no,到目前爲止沒有很好的方法找到會費canMakePayments是一個類方法(+),似乎所有的OCMock方法都是用於實例方法( - )。如何模擬類方法(+)?

你們任何建議或討論將不勝感激。謝謝。

// SKPaymentQueue.h 
// StoreKit 
if ([SKPaymentQueue canMakePayments]){ 
    .... 
} 
else{ 
    ... 
} 
+4

點吧,笑? (對不起,我無法抗拒) – Abizern

回答

4

由於您不能通過提供不同的實例來攔截方法,因此您可以爲類方法執行的操作是提供不同的類。事情是這樣的:

+ (Class)paymentQueueClass 
{ 
    return [SKPaymentQueue class]; 
} 

調用點就變成了:

Class paymentQueueClass = [[self class] paymentQueueClass]; 
if ([paymentQueueClass canMakePayments]) 
... 

這引入了一個「測試縫」,或點控制,允許我們指定比SKPaymentQueue其他類。現在我們來做一個替換:

static BOOL fakeCanMakePayments; 

@interface FakePaymentQueue : SKPaymentQueue 
@end 

@implementation FakePaymentQueue 

+ (void)setFakeCanMakePayments:(BOOL)fakeValue 
{ 
    fakeCanMakePayments = fakeValue; 
} 

+ (BOOL)canMakePayments 
{ 
    return fakeCanMakePayments; 
} 

@end 

嚴格地說,這不是一個「模擬對象」 - 它是一個「假對象」。不同之處在於模擬對象驗證了它的調用方式。假對象只是提供殘留結果。

現在讓我們創建一個我們想測試的原始類的測試子類。

@interface TestingSubclass : OriginalClass 
@end 

@implementation TestingSubclass 

+ (Class)paymentQueueClass 
{ 
    return [FakePaymentQueue class]; 
} 

@end 

所以你看,這取代了SKPaymentQueueFakePaymentQueue。您的測試現在可以針對TestingSubclass運行。

+1

什麼是被測試的班級?也就是說,你是在寫一個針對SKPaymentQueue的測試,還是針對另一個調用SKPaymentQueue的類? –

+0

嘿裏德;謝謝你的回覆。 您的意思是我們需要在我們的測試課程中實施另一個paymentQueueClass?或者破解原有的框架方法類(UnitTests)? 似乎我不完全理解你的解決方案,你能給我更多的提示,非常感謝。 – jianhua

+0

我的測試課是針對不同的課程,調用SKPaymentQueue? – jianhua

12

一種方法是包裹類的方法在自己的實例方法:

-(BOOL)canMakePayments { 
    return [SKPaymentQueue canMakePayments]; 
} 

然後你嘲笑這個方法:

-(void)testCanHandlePaymentsDisabled { 
    Foo *foo = [[Foo alloc] init]; 
    id mockFoo = [OCMockObject partialMockForObject:foo]; 
    BOOL paymentsEnabled = NO; 
    [[[mockFoo stub] andReturnValue:OCMOCK_VALUE(paymentsEnabled)] canMakePayments]; 

    // set up expectations for payments disabled case 
    ... 

    [foo attemptPurchase]; 
} 
+0

啊!非常簡單! –

+0

感謝您的回覆,是的,代碼應該以更容易進行單元測試的方式編寫。 – jianhua

+0

非常有幫助,謝謝! – Rahul