Răsfoiți Sursa

Improve GIDDataFetcher and add GIDFakeDataFetcher

pinlu 3 ani în urmă
părinte
comite
78d24a3c72

+ 4 - 6
GoogleSignIn/Sources/GIDDataFetcher/API/GIDDataFetcher.h

@@ -22,16 +22,14 @@ NS_ASSUME_NONNULL_BEGIN
 
 @protocol GIDDataFetcher <NSObject>
 
-/// Fetches the data from an URL
+/// Fetches the data from an URL.
 ///
 /// @param URL The endpoint to fetch data.
-/// @param authState The state of the current OAuth session.
 /// @param comment The comment for logging purpose.
 /// @param completion The block that is called on completion asynchronously.
-- (void)startFetchURL:(NSURL *)URL
-    fromAuthState:(OIDAuthState *)authState
-      withComment:(NSString *)comment
-       completion:(void (^)(NSData *, NSError *))completion;
+- (void)fetchURL:(NSURL *)URL
+     withComment:(NSString *)comment
+      completion:(void (^)(NSData *_Nullable, NSError *_Nullable))completion;
 
 @end
 

+ 37 - 0
GoogleSignIn/Sources/GIDDataFetcher/Implementations/Fakes/GIDFakeDataFetcher.h

@@ -0,0 +1,37 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "GoogleSignIn/Sources/GIDDataFetcher/API/GIDDataFetcher.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef void(^GIDDataFetcherFakeResponse)(NSData *_Nullable data, NSError *_Nullable error);
+
+typedef void (^GIDDataFetcherTestBlock)(GIDDataFetcherFakeResponse response);
+
+@interface GIDFakeDataFetcher : NSObject<GIDDataFetcher>
+
+/// Set the test block which provides the response value.
+- (void)setTestBlock:(GIDDataFetcherTestBlock)block;
+
+/// The url to fetch data.
+- (nullable NSURL *)requestURL;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 27 - 0
GoogleSignIn/Sources/GIDDataFetcher/Implementations/Fakes/GIDFakeDataFetcher.m

@@ -0,0 +1,27 @@
+#import "GoogleSignIn/Sources/GIDDataFetcher/Implementations/Fakes/GIDFakeDataFetcher.h"
+
+@interface GIDFakeDataFetcher ()
+
+@property(nonatomic) GIDDataFetcherTestBlock testBlock;
+
+@property(nonatomic) NSURL *requestURL;
+
+@end
+
+@implementation GIDFakeDataFetcher
+
+- (void)setTestBlock:(GIDDataFetcherTestBlock)block {
+  _testBlock = block;
+}
+
+- (void)fetchURL:(NSURL *)URL
+     withComment:(NSString *)comment
+      completion:(void (^)(NSData *_Nullable, NSError *_Nullable))completion {
+  self.requestURL = URL;
+  NSAssert(self.testBlock != nil, @"Set the test block before invoking this method.");
+  self.testBlock(^(NSData *_Nullable data, NSError *_Nullable error){
+    completion(data,error);
+  });
+}
+
+@end

+ 4 - 13
GoogleSignIn/Sources/GIDDataFetcher/Implementations/GIDDataFetcher.m

@@ -15,20 +15,11 @@ static const NSTimeInterval kFetcherMaxRetryInterval = 15.0;
 
 @implementation GIDDataFetcher
 
-- (void)startFetchURL:(NSURL *)URL
-    fromAuthState:(OIDAuthState *)authState
-      withComment:(NSString *)comment
-       completion:(void (^)(NSData *, NSError *))completion {
+- (void)fetchURL:(NSURL *)URL
+     withComment:(NSString *)comment
+      completion:(void (^)(NSData *_Nullable, NSError *_Nullable))completion {
   NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
-  GTMSessionFetcher *fetcher;
-  GTMAppAuthFetcherAuthorization *authorization =
-      [[GTMAppAuthFetcherAuthorization alloc] initWithAuthState:authState];
-  id<GTMSessionFetcherServiceProtocol> fetcherService = authorization.fetcherService;
-  if (fetcherService) {
-    fetcher = [fetcherService fetcherWithRequest:request];
-  } else {
-    fetcher = [GTMSessionFetcher fetcherWithRequest:request];
-  }
+  GTMSessionFetcher *fetcher = [GTMSessionFetcher fetcherWithRequest:request];
   fetcher.retryEnabled = YES;
   fetcher.maxRetryInterval = kFetcherMaxRetryInterval;
   fetcher.comment = comment;

+ 8 - 10
GoogleSignIn/Sources/GIDSignIn.m

@@ -423,10 +423,9 @@ static NSString *const kConfigOpenIDRealmKey = @"GIDOpenIDRealm";
                      kEnvironmentLoggingParameter,
                      GIDEnvironment()];
   NSURL *revokeURL = [NSURL URLWithString:revokeURLString];
-  [_dataFetcher startFetchURL:revokeURL
-                fromAuthState:authState
-                  withComment:@"GIDSignIn: revoke tokens"
-                   completion:^(NSData *data, NSError *error) {
+  [_dataFetcher fetchURL:revokeURL
+             withComment:@"GIDSignIn: revoke tokens"
+              completion:^(NSData *data, NSError *error) {
     // Revoking an already revoked token seems always successful, which helps us here.
     if (!error) {
       [self signOut];
@@ -453,8 +452,8 @@ static NSString *const kConfigOpenIDRealmKey = @"GIDOpenIDRealm";
 #pragma mark - Private methods
 
 - (id)initPrivate {
-  GIDKeychainHandler *keychainHandler = [[GIDKeychainHandler alloc] init];
-  GIDDataFetcher *dataFetcher = [[GIDDataFetcher alloc] init];
+  id<GIDKeychainHandler> keychainHandler = [[GIDKeychainHandler alloc] init];
+  id<GIDDataFetcher> dataFetcher = [[GIDDataFetcher alloc] init];
   return [self initWithKeychainHandler:keychainHandler
                            dataFetcher:dataFetcher];
 }
@@ -828,10 +827,9 @@ static NSString *const kConfigOpenIDRealmKey = @"GIDOpenIDRealm";
               [GIDSignInPreferences googleUserInfoServer],
               authState.lastTokenResponse.accessToken]];
       
-      [self->_dataFetcher startFetchURL:infoURL
-                          fromAuthState:authState
-                            withComment:@"GIDSignIn: fetch basic profile info"
-                             completion:^(NSData *data, NSError *error) {
+      [self->_dataFetcher fetchURL:infoURL
+                       withComment:@"GIDSignIn: fetch basic profile info"
+                        completion:^(NSData *data, NSError *error) {
         if (data && !error) {
           NSError *jsonDeserializationError;
           NSDictionary<NSString *, NSString *> *profileDict =

+ 33 - 69
GoogleSignIn/Tests/Unit/GIDDataFetcherTest.m

@@ -16,10 +16,6 @@
 
 #import <XCTest/XCTest.h>
 
-#import "GoogleSignIn/Tests/Unit/GIDFakeFetcher.h"
-#import "GoogleSignIn/Tests/Unit/GIDFakeFetcherService.h"
-#import "GoogleSignIn/Tests/Unit/OIDAuthState+Testing.h"
-
 #ifdef SWIFT_PACKAGE
 @import AppAuth;
 @import GTMAppAuth;
@@ -30,18 +26,12 @@
 #import <OCMock/OCMock.h>
 #endif
 
-static NSString *const kTestURL = @"testURL.com";
-static NSString * const kErrorDomain = @"ERROR_DOMAIN";
-static NSInteger const kErrorCode = 212;
+static NSString *const kTestURL = @"https://testURL.com";
+static NSString *const kErrorDomain = @"ERROR_DOMAIN";
+static NSInteger const kErrorCode = 400;
 
 @interface GIDDataFetcherTest : XCTestCase {
   GIDDataFetcher *_dataFetcher;
-  
-  // Mock |GTMAppAuthFetcherAuthorization|.
-  id _authorization;
-  
-  // Fake fetcher service to emulate network requests.
-  GIDFakeFetcherService *_fakeFetcherService;
 }
 
 @end
@@ -51,83 +41,57 @@ static NSInteger const kErrorCode = 212;
 - (void)setUp {
   [super setUp];
   _dataFetcher = [[GIDDataFetcher alloc] init];
-  _fakeFetcherService = [[GIDFakeFetcherService alloc] init];
-  
-  _authorization = OCMStrictClassMock([GTMAppAuthFetcherAuthorization class]);
-  OCMStub([_authorization alloc]).andReturn(_authorization);
-  OCMStub([_authorization initWithAuthState:OCMOCK_ANY]).andReturn(_authorization);
-  OCMStub([_authorization fetcherService]).andReturn(_fakeFetcherService);
-}
-
-- (void)tearDown {
-  _authorization = nil;
-  [super tearDown];
 }
 
 - (void)testFetchData_success {
   NSURL *url = [NSURL URLWithString:kTestURL];
-  OIDAuthState *authState = [OIDAuthState testInstance];
   XCTestExpectation *expectation =
       [self expectationWithDescription:@"Callback called with no error"];
-
-  [_dataFetcher startFetchURL:url
-                fromAuthState:authState
-                  withComment:@"Test data fetcher."
-                   completion:^(NSData *data, NSError *error) {
-    if (error == nil) {
-      [expectation fulfill];
-    }
+  
+  
+  GTMSessionFetcherTestBlock block =
+      ^(GTMSessionFetcher *fetcherToTest, GTMSessionFetcherTestResponse testResponse) {
+        NSData *data = [[NSData alloc] init];
+        testResponse(nil, data, nil);
+      };
+  [GTMSessionFetcher setGlobalTestBlock:block];
+  
+  [_dataFetcher fetchURL:url
+             withComment:@"Test data fetcher."
+              completion:^(NSData *data, NSError *error) {
+    XCTAssertNil(error);
+    [expectation fulfill];
   }];
 
-  XCTAssertTrue([self isFetcherStarted], @"should start fetching");
-  // Emulate result back from server.
-  [self didFetch:nil error:nil];
   [self waitForExpectationsWithTimeout:1 handler:nil];
 }
 
 - (void)testFetchData_error {
   NSURL *url = [NSURL URLWithString:kTestURL];
-  OIDAuthState *authState = [OIDAuthState testInstance];
   XCTestExpectation *expectation =
       [self expectationWithDescription:@"Callback called with an error"];
-  [_dataFetcher startFetchURL:url
-                fromAuthState:authState
-                  withComment:@"Test data fetcher."
-                   completion:^(NSData *data, NSError *error) {
-    if (error != nil) {
-      [expectation fulfill];
-    }
+  
+  GTMSessionFetcherTestBlock block =
+      ^(GTMSessionFetcher *fetcherToTest, GTMSessionFetcherTestResponse testResponse) {
+        NSData *data = [[NSData alloc] init];
+        NSError *error = [self error];
+        testResponse(nil, data, error);
+      };
+  [GTMSessionFetcher setGlobalTestBlock:block];
+  
+  
+  [_dataFetcher fetchURL:url
+             withComment:@"Test data fetcher."
+              completion:^(NSData *data, NSError *error) {
+    XCTAssertNotNil(error);
+    XCTAssertEqual(error.code, kErrorCode);
+    [expectation fulfill];
   }];
-
-  XCTAssertTrue([self isFetcherStarted], @"should start fetching");
-  // Emulate result back from server.
-  NSError *error = [self error];
-  [self didFetch:nil error:error];
   [self waitForExpectationsWithTimeout:1 handler:nil];
 }
 
 #pragma mark - Helpers
 
-// Whether or not a fetcher has been started.
-- (BOOL)isFetcherStarted {
-  NSUInteger count = _fakeFetcherService.fetchers.count;
-  XCTAssertTrue(count <= 1, @"Only one fetcher is supported");
-  return !!count;
-}
-
-// Emulates server returning the data as in JSON.
-- (void)didFetch:(id)dataObject error:(NSError *)error {
-  NSData *data = nil;
-  if (dataObject) {
-    NSError *jsonError = nil;
-    data = [NSJSONSerialization dataWithJSONObject:dataObject
-                                           options:0
-                                             error:&jsonError];
-    XCTAssertNil(jsonError, @"must provide valid data");
-  }
-  [_fakeFetcherService.fetchers[0] didFinishWithData:data error:error];
-}
-
 - (NSError *)error {
   return [NSError errorWithDomain:kErrorDomain code:kErrorCode userInfo:nil];
 }

+ 91 - 118
GoogleSignIn/Tests/Unit/GIDSignInTest.m

@@ -33,12 +33,13 @@
 #import "GoogleSignIn/Sources/GIDKeychainHandler/Implementations/Fakes/GIDFakeKeychainHandler.h"
 #import "GoogleSignIn/Sources/GIDDataFetcher/Implementations/GIDDataFetcher.h"
 
+#import "GoogleSignIn/Sources/GIDDataFetcher/Implementations/Fakes/GIDFakeDataFetcher.h"
+
+
 #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
 #import "GoogleSignIn/Sources/GIDEMMErrorHandler.h"
 #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST
 
-#import "GoogleSignIn/Tests/Unit/GIDFakeFetcher.h"
-#import "GoogleSignIn/Tests/Unit/GIDFakeFetcherService.h"
 #import "GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h"
 #import "GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h"
 #import "GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h"
@@ -195,9 +196,12 @@ static NSString *const kNewScope = @"newScope";
   // Mock |GTMAppAuthFetcherAuthorization|.
   id _authorization;
   
-  // Fake for |GIDKeychainHandler|
+  // Fake for |GIDKeychainHandler|.
   GIDFakeKeychainHandler *_keychainHandler;
 
+  // Fake for |GIDDataFetcher|.
+  GIDFakeDataFetcher *_dataFetcher;
+  
 #if TARGET_OS_IOS || TARGET_OS_MACCATALYST
   // Mock |UIViewController|.
   id _presentingViewController;
@@ -218,9 +222,6 @@ static NSString *const kNewScope = @"newScope";
   // Whether callback block has been called.
   BOOL _completionCalled;
 
-  // Fake fetcher service to emulate network requests.
-  GIDFakeFetcherService *_fetcherService;
-
   // Fake [NSBundle mainBundle];
   GIDFakeMainBundle *_fakeMainBundle;
 
@@ -300,7 +301,6 @@ static NSString *const kNewScope = @"newScope";
                  callback:COPY_TO_ARG_BLOCK(self->_savedTokenCallback)]);
 
   // Fakes
-  _fetcherService = [[GIDFakeFetcherService alloc] init];
   _fakeMainBundle = [[GIDFakeMainBundle alloc] init];
   [_fakeMainBundle startFakingWithClientID:kClientId];
   [_fakeMainBundle fakeAllSchemesSupported];
@@ -311,10 +311,10 @@ static NSString *const kNewScope = @"newScope";
 
   _keychainHandler = [[GIDFakeKeychainHandler alloc] init];
   
-  // TODO:Add the GIDFakeDataFetcher class and replace the real one.
-  GIDDataFetcher* dataFetcher = [[GIDDataFetcher alloc] init];
+  _dataFetcher = [[GIDFakeDataFetcher alloc] init];
+  
   _signIn = [[GIDSignIn alloc] initWithKeychainHandler:_keychainHandler
-                                           dataFetcher:dataFetcher];
+                                           dataFetcher:_dataFetcher]; 
   _hint = nil;
 
   __weak GIDSignInTest *weakSelf = self;
@@ -745,135 +745,140 @@ static NSString *const kNewScope = @"newScope";
 #pragma mark - Tests - disconnectWithCallback:
 
 // Verifies disconnect calls callback with no errors if access token is present.
-- (void)testDisconnect_accessToken {
+- (void)testDisconnect_accessTokenIsPresent {
   [_keychainHandler saveAuthState:_authState];
-  [[[_authState expect] andReturn:_tokenResponse] lastTokenResponse];
-  [[[_tokenResponse expect] andReturn:kAccessToken] accessToken];
-  [[[_authorization expect] andReturn:_fetcherService] fetcherService];
+  OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse);
+  OCMStub([_tokenResponse accessToken]).andReturn(kAccessToken);
+  
+  GIDDataFetcherTestBlock testBlock =
+      ^(GIDDataFetcherFakeResponse response) {
+        NSData *data = [[NSData alloc] init];
+        response(data, nil);
+     };
+  [_dataFetcher setTestBlock:testBlock];
+  
   XCTestExpectation *expectation =
       [self expectationWithDescription:@"Callback called with nil error"];
   [_signIn disconnectWithCompletion:^(NSError * _Nullable error) {
-    if (error == nil) {
-      [expectation fulfill];
-    }
+    XCTAssertNil(error);
+    NSURL *url = [_dataFetcher requestURL];
+    [self verifyURL:url withToken:kAccessToken];
+    [expectation fulfill];
   }];
-  [self verifyAndRevokeToken:kAccessToken hasCallback:YES];
-  [_authorization verify];
-  [_authState verify];
-  [_tokenResponse verify];
+  [self waitForExpectationsWithTimeout:1 handler:nil];
   XCTAssertNil([_keychainHandler loadAuthState]);
 }
 
 // Verifies disconnect if access token is present.
-- (void)testDisconnectNoCallback_accessToken {
+- (void)testDisconnectNoCallback_accessTokenIsPresent {
   [_keychainHandler saveAuthState:_authState];
-  [[[_authState expect] andReturn:_tokenResponse] lastTokenResponse];
-  [[[_tokenResponse expect] andReturn:kAccessToken] accessToken];
-  [[[_authorization expect] andReturn:_fetcherService] fetcherService];
+  OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse);
+  OCMStub([_tokenResponse accessToken]).andReturn(kAccessToken);
+  
+  GIDDataFetcherTestBlock testBlock =
+      ^(GIDDataFetcherFakeResponse response) {
+        NSData *data = [[NSData alloc] init];
+        response(data, nil);
+     };
+  [_dataFetcher setTestBlock:testBlock];
+  
   [_signIn disconnectWithCompletion:nil];
-  [self verifyAndRevokeToken:kAccessToken hasCallback:NO];
-  [_authorization verify];
-  [_authState verify];
-  [_tokenResponse verify];
+  NSURL *url = [_dataFetcher requestURL];
+  [self verifyURL:url withToken:kAccessToken];
   XCTAssertNil([_keychainHandler loadAuthState]);
 }
 
-// Verifies disconnect calls callback with no errors if refresh token is present.
-- (void)testDisconnect_refreshToken {
+//// Verifies disconnect calls callback with no errors if refresh token is present.
+- (void)testDisconnect_refreshTokenIsPresent {
   [_keychainHandler saveAuthState:_authState];
-  [[[_authState expect] andReturn:_tokenResponse] lastTokenResponse];
-  [[[_tokenResponse expect] andReturn:nil] accessToken];
-  [[[_authState expect] andReturn:_tokenResponse] lastTokenResponse];
-  [[[_tokenResponse expect] andReturn:kRefreshToken] refreshToken];
-  [[[_authorization expect] andReturn:_fetcherService] fetcherService];
+  OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse);
+  OCMStub([_tokenResponse accessToken]).andReturn(nil);
+  OCMStub([_tokenResponse refreshToken]).andReturn(kRefreshToken);
+  
+  GIDDataFetcherTestBlock testBlock =
+      ^(GIDDataFetcherFakeResponse response) {
+        NSData *data = [[NSData alloc] init];
+        response(data, nil);
+     };
+  [_dataFetcher setTestBlock:testBlock];
+  
   XCTestExpectation *expectation =
       [self expectationWithDescription:@"Callback called with nil error"];
   [_signIn disconnectWithCompletion:^(NSError * _Nullable error) {
-    if (error == nil) {
-      [expectation fulfill];
-    }
+    XCTAssertNil(error);
+    NSURL *url = [_dataFetcher requestURL];
+    [self verifyURL:url withToken:kRefreshToken];
+    [expectation fulfill];
   }];
-  [self verifyAndRevokeToken:kRefreshToken hasCallback:YES];
-  [_authorization verify];
-  [_authState verify];
+  [self waitForExpectationsWithTimeout:1 handler:nil];
   XCTAssertNil([_keychainHandler loadAuthState]);
 }
 
 // Verifies disconnect errors are passed along to the callback.
 - (void)testDisconnect_errors {
   [_keychainHandler saveAuthState:_authState];
-  [[[_authState expect] andReturn:_tokenResponse] lastTokenResponse];
-  [[[_tokenResponse expect] andReturn:kAccessToken] accessToken];
-  [[[_authorization expect] andReturn:_fetcherService] fetcherService];
+  OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse);
+  OCMStub([_tokenResponse accessToken]).andReturn(kAccessToken);
+  GIDDataFetcherTestBlock testBlock =
+      ^(GIDDataFetcherFakeResponse response) {
+        NSError *error = [self error];
+        response(nil, error);
+     };
+  [_dataFetcher setTestBlock:testBlock];
+  
   XCTestExpectation *expectation =
       [self expectationWithDescription:@"Callback called with an error"];
   [_signIn disconnectWithCompletion:^(NSError * _Nullable error) {
-    if (error != nil) {
-      [expectation fulfill];
-    }
+    XCTAssertNotNil(error);
+    [expectation fulfill];
   }];
-  XCTAssertTrue([self isFetcherStarted], @"should start fetching");
-  // Emulate result back from server.
-  NSError *error = [self error];
-  [self didFetch:nil error:error];
   [self waitForExpectationsWithTimeout:1 handler:nil];
-  [_authorization verify];
-  [_authState verify];
-  [_tokenResponse verify];
   XCTAssertNotNil([_keychainHandler loadAuthState]);
 }
 
 // Verifies disconnect with errors
 - (void)testDisconnectNoCallback_errors {
   [_keychainHandler saveAuthState:_authState];
-  [[[_authState expect] andReturn:_tokenResponse] lastTokenResponse];
-  [[[_tokenResponse expect] andReturn:kAccessToken] accessToken];
-  [[[_authorization expect] andReturn:_fetcherService] fetcherService];
+  OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse);
+  OCMStub([_tokenResponse accessToken]).andReturn(kAccessToken);
+  GIDDataFetcherTestBlock testBlock =
+      ^(GIDDataFetcherFakeResponse response) {
+        NSError *error = [self error];
+        response(nil, error);
+     };
+  [_dataFetcher setTestBlock:testBlock];
+  
   [_signIn disconnectWithCompletion:nil];
-  XCTAssertTrue([self isFetcherStarted], @"should start fetching");
-  // Emulate result back from server.
-  NSError *error = [self error];
-  [self didFetch:nil error:error];
-  [_authorization verify];
-  [_authState verify];
-  [_tokenResponse verify];
   XCTAssertNotNil([_keychainHandler loadAuthState]);
 }
 
 // Verifies disconnect calls callback with no errors and clears keychain if no tokens are present.
 - (void)testDisconnect_noTokens {
   [_keychainHandler saveAuthState:_authState];
-  [[[_authState expect] andReturn:_tokenResponse] lastTokenResponse];
-  [[[_tokenResponse expect] andReturn:nil] accessToken];
-  [[[_authState expect] andReturn:_tokenResponse] lastTokenResponse];
-  [[[_tokenResponse expect] andReturn:nil] refreshToken];
+  OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse);
+  OCMStub([_tokenResponse accessToken]).andReturn(nil);
+  OCMStub([_tokenResponse refreshToken]).andReturn(nil);
   XCTestExpectation *expectation =
       [self expectationWithDescription:@"Callback called with nil error"];
   [_signIn disconnectWithCompletion:^(NSError * _Nullable error) {
-    if (error == nil) {
-      [expectation fulfill];
-    }
+    XCTAssertNil(error);
+    // Since _dataFetcher is not invoked so there is no request url saved.
+    XCTAssertNil([_dataFetcher requestURL]);
+    [expectation fulfill];
   }];
   [self waitForExpectationsWithTimeout:1 handler:nil];
-  XCTAssertFalse([self isFetcherStarted], @"should not fetch");
-  [_authorization verify];
-  [_authState verify];
-  [_tokenResponse verify];
   XCTAssertNil([_keychainHandler loadAuthState]);
 }
 
 // Verifies disconnect clears keychain if no tokens are present.
 - (void)testDisconnectNoCallback_noTokens {
   [_keychainHandler saveAuthState:_authState];
-  [[[_authState expect] andReturn:_tokenResponse] lastTokenResponse];
-  [[[_tokenResponse expect] andReturn:nil] accessToken];
-  [[[_authState expect] andReturn:_tokenResponse] lastTokenResponse];
-  [[[_tokenResponse expect] andReturn:nil] refreshToken];
+  OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse);
+  OCMStub([_tokenResponse accessToken]).andReturn(nil);
+  OCMStub([_tokenResponse refreshToken]).andReturn(nil);
   [_signIn disconnectWithCompletion:nil];
-  XCTAssertFalse([self isFetcherStarted], @"should not fetch");
-  [_authorization verify];
-  [_authState verify];
-  [_tokenResponse verify];
+  // Since _dataFetcher is not invoked so there is no request url saved.
+  XCTAssertNil([_dataFetcher requestURL]);
   XCTAssertNil([_keychainHandler loadAuthState]);
 }
 
@@ -1091,39 +1096,12 @@ static NSString *const kNewScope = @"newScope";
 
 #pragma mark - Helpers
 
-// Whether or not a fetcher has been started.
-- (BOOL)isFetcherStarted {
-  NSUInteger count = _fetcherService.fetchers.count;
-  XCTAssertTrue(count <= 1, @"Only one fetcher is supported");
-  return !!count;
-}
-
-// Gets the URL being fetched.
-- (NSURL *)fetchedURL {
-  return [_fetcherService.fetchers[0] requestURL];
-}
-
-// Emulates server returning the data as in JSON.
-- (void)didFetch:(id)dataObject error:(NSError *)error {
-  NSData *data = nil;
-  if (dataObject) {
-    NSError *jsonError = nil;
-    data = [NSJSONSerialization dataWithJSONObject:dataObject
-                                           options:0
-                                             error:&jsonError];
-    XCTAssertNil(jsonError, @"must provide valid data");
-  }
-  [_fetcherService.fetchers[0] didFinishWithData:data error:error];
-}
-
 - (NSError *)error {
   return [NSError errorWithDomain:kErrorDomain code:kErrorCode userInfo:nil];
 }
 
-// Verifies a fetcher has started for revoking token and emulates a server response.
-- (void)verifyAndRevokeToken:(NSString *)token hasCallback:(BOOL)hasCallback {
-  XCTAssertTrue([self isFetcherStarted], @"should start fetching");
-  NSURL *url = [self fetchedURL];
+// Verifies the url to fetch the data.
+- (void)verifyURL:(NSURL *)url withToken:(NSString *)token {
   XCTAssertEqualObjects([url scheme], @"https", @"scheme must match");
   XCTAssertEqualObjects([url host], @"accounts.google.com", @"host must match");
   XCTAssertEqualObjects([url path], @"/o/oauth2/revoke", @"path must match");
@@ -1135,11 +1113,6 @@ static NSString *const kNewScope = @"newScope";
                         @"SDK version logging parameter should match");
   XCTAssertEqualObjects([params valueForKey:kEnvironmentLoggingParameter], GIDEnvironment(),
                         @"Environment logging parameter should match");
-  // Emulate result back from server.
-  [self didFetch:nil error:nil];
-  if (hasCallback) {
-    [self waitForExpectationsWithTimeout:1 handler:nil];
-  }
 }
 
 - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow