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.
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.
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
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];
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.
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
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);
}