objective-c unit-testing mocking static-methods ocmock

objective c - ¿Cómo simular el método de clase(+)?



objective-c unit-testing (2)

Esta pregunta ya tiene una respuesta aquí:

Necesito escribir pruebas unitarias para el siguiente código, quiero hacer un simulacro para el método de clase canMakePayments, devolver yes o no, hasta ahora ningún método bueno encontró cuotas para canMakePayments es un método de clase (+), parece que todos los métodos de OCMock se usan para método de instancia (-).

Ustedes, cualquier sugerencia o discusión será apreciada. Gracias.

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


Como no puede interceptar el método proporcionando una instancia diferente, lo que puede hacer por un método de clase es proporcionar una clase diferente. Algo como esto:

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

El punto de llamada se convierte en:

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

Esto introduce una "costura de prueba" o un punto de control que nos permite especificar una clase distinta a SKPaymentQueue . Ahora hagamos un reemplazo:

static BOOL fakeCanMakePayments; @interface FakePaymentQueue : SKPaymentQueue @end @implementation FakePaymentQueue + (void)setFakeCanMakePayments:(BOOL)fakeValue { fakeCanMakePayments = fakeValue; } + (BOOL)canMakePayments { return fakeCanMakePayments; } @end

Estrictamente hablando, este no es un "objeto falso", es un "objeto falso". La diferencia es que un objeto simulado verifica cómo se llama. Un objeto falso solo proporciona resultados truncados.

Ahora vamos a crear una subclase de prueba de la clase original que queremos probar.

@interface TestingSubclass : OriginalClass @end @implementation TestingSubclass + (Class)paymentQueueClass { return [FakePaymentQueue class]; } @end

SKPaymentQueue puede ver, esto reemplaza a SKPaymentQueue con FakePaymentQueue . Sus pruebas ahora pueden ejecutarse contra TestingSubclass .


Un enfoque es envolver el método de clase en su propio método de instancia:

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

Entonces te burlas de ese método:

-(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]; }