@@ -82,7 +82,6 @@ class TokenMigrationActivityTest {
8282 private lateinit var mockClientManager: com.salesforce.androidsdk.rest.ClientManager
8383 private lateinit var realSdkManager: SalesforceSDKManager
8484 private lateinit var savedFactory: ViewModelProvider .Factory
85- private var savedAppAttestationClient: AppAttestationClient ? = null
8685
8786 @Before
8887 fun setUp () {
@@ -116,20 +115,34 @@ class TokenMigrationActivityTest {
116115 // Get the REAL SalesforceSDKManager instance and save reference + properties
117116 realSdkManager = SalesforceSDKManager .getInstance()
118117 savedFactory = realSdkManager.loginViewModelFactory
119- savedAppAttestationClient = realSdkManager.appAttestationClient
120118
121- // CRITICAL: Set appAttestationClient to null on the REAL instance to prevent blocking network calls
122- // This must be done before creating the spy to ensure the spy sees the null value
123- realSdkManager.appAttestationClient = null
119+ // Mock the SalesforceSDKManager object to control specific properties
120+ mockkObject(SalesforceSDKManager )
124121
125- // Mock only the clientManager on the real instance using spyk
126- val sdkManagerSpy = spyk(realSdkManager)
127- every { sdkManagerSpy.clientManager } returns mockClientManager
122+ // Mock appContext for logging
123+ every { SalesforceSDKManager .getInstance().appContext } returns getApplicationContext()
124+
125+ // Mock userAccountManager (called during lifecycle for biometric auth checks)
126+ every { SalesforceSDKManager .getInstance().userAccountManager } returns mockUserAccountManager
127+
128+ // CRITICAL: Mock appAttestationClient to return null to prevent blocking network calls
129+ // in LoginViewModel.getAuthorizationUrl() and OAuth2.makeTokenEndpointRequest()
130+ every { SalesforceSDKManager .getInstance().appAttestationClient } returns null
131+
132+ // Mock clientManager to return our mock
133+ every { SalesforceSDKManager .getInstance().clientManager } returns mockClientManager
128134 every { mockClientManager.peekRestClient(any<UserAccount >()) } returns mockRestClient
129135
130- // Replace getInstance() to return our spy instead of completely mocking the object
131- mockkStatic(SalesforceSDKManager ::class )
132- every { SalesforceSDKManager .getInstance() } returns sdkManagerSpy
136+ // Allow tests to set loginViewModelFactory
137+ every { SalesforceSDKManager .getInstance().loginViewModelFactory = any() } answers { }
138+ every { SalesforceSDKManager .getInstance().loginViewModelFactory } returns savedFactory
139+
140+ // Mock push notification receiver (called during lifecycle for push setup)
141+ every { SalesforceSDKManager .getInstance().pushNotificationReceiver } returns null
142+
143+ // Allow lifecycle methods to be called without errors
144+ every { SalesforceSDKManager .getInstance().isDevSupportEnabled() } returns false
145+ every { SalesforceSDKManager .getInstance().onResume(any()) } returns Unit
133146
134147 // Default mock for sendSync to prevent hanging - tests can override this
135148 val mockResponse = mockk< com.salesforce.androidsdk.rest.RestResponse > (relaxed = true )
@@ -144,10 +157,13 @@ class TokenMigrationActivityTest {
144157
145158 @After
146159 fun tearDown () {
147- // Restore the loginViewModelFactory and appAttestationClient on the REAL instance (not via getInstance())
160+ // Restore the loginViewModelFactory on the REAL instance (not via getInstance())
148161 // This must be done before unmockkAll() so we have the reference
149162 realSdkManager.loginViewModelFactory = savedFactory
150- realSdkManager.appAttestationClient = savedAppAttestationClient
163+
164+ // NOTE: We don't save/restore appAttestationClient because the setter is internal and not
165+ // accessible from test module. The unmockkAll() below clears all mocking, reverting
166+ // the mocked SalesforceSDKManager object back to normal behavior.
151167
152168 // Clean up all mocks
153169 unmockkAll()
0 commit comments