web-dev-qa-db-fra.com

Passage de primitives au stub d'OCMock

J'apprends à utiliser OCMock pour tester le projet de mon iPhone. Le scénario est le suivant: une classe HeightMap avec une méthode getHeightAtX:andY: et une classe Render utilisant HeightMap. J'essaie de tester un peu le rendu avec quelques mouches HeightMap. Cela marche:

id mock = [OCMockObject mockForClass:[Chunk class]];
int h = 0;
[[[mock stub] andReturnValue:OCMOCK_VALUE(h)] getHeightAtX:0 andY:0];

Bien sûr, ne fonctionne que pour x=0 et y=0. Je veux tester en utilisant une carte de hauteur "plate". Cela signifie que je dois faire quelque chose comme ceci:

id chunk = [OCMockObject mockForClass:[Chunk class]];
int h = 0;
[[[chunk stub] andReturnValue:OCMOCK_VALUE(h)] getHeightAtX:[OCMArg any] andY:[OCMArg any]];

Mais cela soulève deux avertissements de compilation:

warning: le passage de l'argument 1 de 'getHeightAtX:andY:' crée un entier à partir d'un pointeur sans transtypage

et une erreur d'exécution:

méthode inattendue appelée: 'getHeightAtX:0 andY:0 stubbed: getHeightAtX:15545040 andY:15545024'

Qu'est-ce que je rate? Je n'ai trouvé aucun moyen de passer une anyValue à cette maquette.

30
Eduardo Costa

OCMock ne prend actuellement pas en charge la correspondance libre des arguments primitifs. Il y a une discussion sur les changements potentiels pour supporter ceci sur les forums d'OCMock , même si cela semble s'être bloqué.

La seule solution que j'ai trouvée consiste à structurer mes tests de manière à ce que je connaisse les valeurs primitives qui seront transmises, même si c'est loin d'être idéal.

18

Cela fait longtemps que cette question n’a pas été posée, mais j’ai moi-même rencontré ce problème et je n’ai trouvé aucune solution. OCMock supporte maintenant ignoringNonObjectArgs donc un exemple de expect serait

[[[mockObject expect] ignoringNonObjectArgs] someMethodWithPrimitiveArgument:5];

le 5 ne fait réellement rien, juste une valeur de remplissage

49
Andrew Park

Utilisez OCMockito à la place.

Il supporte la correspondance d'arguments primitifs.

Par exemple, dans votre cas:

id chunk = mock([Chunk class]);
[[given([chunk getHeightAtX:0]) withMatcher:anything() forArgument:0] willReturnInt:0];
2
yonix

En plus de Andrew Park answer, vous pourriez le rendre un peu plus général et plus joli:

#define OCMStubIgnoringNonObjectArgs(invocation) \
({ \
    _OCMSilenceWarnings( \
        [OCMMacroState beginStubMacro]; \
        [[[OCMMacroState globalState] recorder] ignoringNonObjectArgs]; \
        invocation; \
        [OCMMacroState endStubMacro]; \
    ); \
})

Vous pouvez l'utiliser comme ça:

OCMStubIgnoringNonObjectArgs(someMethodParam:0 param2:0).andDo(someBlock)

Vous pouvez faire la même chose pour attendre. Ce cas est pour stubbing en tant que demande de démarrage de sujet. Il a été testé avec OCMock 3.1.1.

1
Alex

Vous pourriez faire comme ceci: id chunk = OCMClassMock([Chunk class]) OCMStub([chunk ignoringNonObjectArgs] getHeightAtX:0 andY:0]])

Lisez plus sur: http://ocmock.org/reference/#argument-constraints

0
Tan Vu

Malgré le fait qu’il soit assez compliqué, l’approche consistant à utiliser les attentes pour stocker le bloc passé à appeler ultérieurement dans le code de test a fonctionné pour moi:

- (void)testVerifyPrimitiveBlockArgument
{
    // mock object that would call the block in production
    id mockOtherObject = OCMClassMock([OtherObject class]);

    // pass the block calling object to the test object
    Object *objectUnderTest = [[Object new] initWithOtherObject:mockOtherObject];

    // store the block when the method is called to use later
    __block void (^completionBlock)(NSUInteger value) = nil;
    OCMExpect([mockOtherObject doSomethingWithCompletion:[OCMArg checkWithBlock:^BOOL(id value) { completionBlock = value; return YES; }]]);

    // call the method that's being tested
    [objectUnderTest doThingThatCallsBlockOnOtherObject];

    // once the expected method has been called from `doThingThatCallsBlockOnOtherObject`, continue
    OCMVerifyAllWithDelay(mockOtherObject, 0.5);
    // simulate callback from mockOtherObject with primitive value, can be done on the main or background queue
    completionBlock(45);
}
0
Matt Robinson