OCMock y prueba de bloque, ejecutando.

Aquí está el método bajo prueba:

- (void)loginWithUser:(NSString *)userName andPass:(NSString *)pass {

    NSDictionary *userPassD = @{@"user":userName,
                                @"pass":pass};
    [_loginCntrl loginWithUserPass:userPassD withSuccess:^(NSString *authToken){
        // save authToken to credential store
    } failure:^(NSString *errorMessage) {
        // alert user pass was wrong
    }];    
}

Lo que quiero probar es que en ese bloqueo exitoso se llama a la otra dependencia / OCMockObject _credStore con los métodos apropiados. Por lo tanto, actualmente las dependencias loginCtrl y credStore son OCMockObjects y puedo detenerlas / esperarlas.

¿Apagaré loginController para ejecutar de alguna manera ese bloque cuando se le llame? He analizado algunas de las preguntas sobre bloques de apuntes con OCMock y no puedo comprender lo que están haciendo y si sería adecuado para esta situación.

En realidad, todo lo que quiero hacer es OCMock para disparar el bloque ([invocación exitosa] ??) para que se realice el código _credStore saveUserPass y se pueda verificar en _credStore.

donde me detuve

- (void)test_loginWithuserPass_succeeds_should_call_credStore_setAuthToken {

    NSDictionary *userPassD = @{@"user":@"mark",
                                @"pass":@"test"};
    id successBlock = ^ {
        // ??? isn't this done in the SUT?
    };

    [[[_loginController stub] andDo:successBlock] loginWithUserPass:userPassD withSuccess:OCMOCK_ANY failure:OCMOCK_ANY];
    [[_credentialStore expect] setAuthToken:@"passed back value from block"];
    [_docServiceSUT loginWithUser:@"mark" andPass:@"test"];
    [_credentialStore verify];
}

ETA: esto es lo que he basado en el ejemplo de Ben a continuación, pero no funciona, obteniendo una excepción EXC_BAD_ACCESS:

// OCUnit test method
- (void)test_loginWithUserPass_success_block_should_call_credentials_setAuthToken {

    void (^proxyBlock)(NSInvocation*) = ^(NSInvocation *invocation) {
        void(^successBlock)(NSString *authToken);
        [invocation getArgument:&successBlock atIndex:3]; // should be 3 because my block is the second param
        successBlock(@"myAuthToken");
    };

    [[[_loginController expect] andDo:proxyBlock] loginWithUserPass:OCMOCK_ANY withSuccess:OCMOCK_ANY failure:OCMOCK_ANY];
    [[_credentialStore expect] setAuthToken:@"myAuthToken"];
    [_docServiceSUT loginWithUser:@"mark" andPass:@"myPass"];
    [_loginController verify];
    [_credentialStore verify];
}

//method under test
- (void)loginWithUser:(NSString *)userName andPass:(NSString *)pass {

    NSDictionary *userPassD = @{@"user":userName,
                                @"pass":pass};

    void(^onSuccess)(NSString *) = ^(NSString *authToken){

        [SVProgressHUD dismiss];
        [_credentials setAuthToken:authToken];

        // Ask user to enter the 6 digit authenticator key
        [self askUserForAuthenticatorKey];
    };

    void(^onFailure)(NSString *) = ^(NSString *errorMessage) {

        [SVProgressHUD dismiss];
        [_alertSender sendAlertWithMessage:errorMessage andTitle:@"Login failed"];
    };

    [SVProgressHUD show];
    [_loginCntrl loginWithUserPass:userPassD withSuccess:onSuccess
      failure:onFailure];
}

Respuestas a la pregunta(3)

Su respuesta a la pregunta