Skip to content

Commit a8d1ffa

Browse files
committed
clean up androd user contexts for testability
1 parent 826f8c5 commit a8d1ffa

File tree

3 files changed

+186
-7
lines changed

3 files changed

+186
-7
lines changed

android-sdk/src/main/java/com/optimizely/ab/android/sdk/OptimizelyManager.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@
6464
import org.slf4j.Logger;
6565
import org.slf4j.LoggerFactory;
6666

67-
import java.beans.DefaultPersistenceDelegate;
6867
import java.io.IOException;
6968
import java.io.InputStream;
7069
import java.util.Collections;

android-sdk/src/main/java/com/optimizely/ab/android/sdk/OptimizelyUserContextAndroid.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -330,12 +330,9 @@ public Map<String, OptimizelyDecision> decideAllAsync() {
330330
// ===========================================
331331

332332
/**
333-
* Core delegation methods that encapsulate all parent class method calls.
334-
* These protected methods can be overridden in test subclasses to mock parent behavior
335-
* without affecting production code or requiring complex dependency injection.
336-
*
337-
* Pattern: Each public API method delegates to its corresponding core method,
338-
* which then calls the appropriate super method from OptimizelyUserContext.
333+
* Core delegation methods that encapsulate all java-sdk parent class method calls.
334+
* These methods enable clean unit testing by providing mockable entry points
335+
* for parent functionality, circumventing Mockito's inability to intercept super calls.
339336
*/
340337

341338
OptimizelyDecision coreDecideSync(@NonNull String key, @NonNull List<OptimizelyDecideOption> options) {

android-sdk/src/test/java/com/optimizely/ab/android/sdk/OptimizelyUserContextAndroidTest.java

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,4 +227,187 @@ public void testDecideAll_withoutOptions() throws Exception {
227227
assertEquals(mockDecisionsMap, result);
228228
}
229229

230+
// ===========================================
231+
// Tests for Async Decide Methods (with callbacks)
232+
// ===========================================
233+
234+
@Test
235+
public void testDecideAsync_withCallbackAndOptions() throws Exception {
236+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
237+
mockOptimizely,
238+
TEST_USER_ID,
239+
testAttributes
240+
));
241+
242+
userContext.decideAsync(TEST_FLAG_KEY, TEST_OPTIONS, mockDecisionCallback);
243+
244+
verify(userContext).coreDecideAsync(TEST_FLAG_KEY, TEST_OPTIONS, mockDecisionCallback);
245+
}
246+
247+
@Test
248+
public void testDecideAsync_withCallbackOnly() throws Exception {
249+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
250+
mockOptimizely,
251+
TEST_USER_ID,
252+
testAttributes
253+
));
254+
255+
userContext.decideAsync(TEST_FLAG_KEY, mockDecisionCallback);
256+
257+
verify(userContext).coreDecideAsync(TEST_FLAG_KEY, Collections.emptyList(), mockDecisionCallback);
258+
}
259+
260+
@Test
261+
public void testDecideForKeysAsync_withCallbackAndOptions() throws Exception {
262+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
263+
mockOptimizely,
264+
TEST_USER_ID,
265+
testAttributes
266+
));
267+
268+
userContext.decideForKeysAsync(TEST_FLAG_KEYS, TEST_OPTIONS, mockDecisionsCallback);
269+
270+
verify(userContext).coreDecideForKeysAsync(TEST_FLAG_KEYS, TEST_OPTIONS, mockDecisionsCallback);
271+
}
272+
273+
@Test
274+
public void testDecideForKeysAsync_withCallbackOnly() throws Exception {
275+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
276+
mockOptimizely,
277+
TEST_USER_ID,
278+
testAttributes
279+
));
280+
281+
userContext.decideForKeysAsync(TEST_FLAG_KEYS, mockDecisionsCallback);
282+
283+
verify(userContext).coreDecideForKeysAsync(TEST_FLAG_KEYS, Collections.emptyList(), mockDecisionsCallback);
284+
}
285+
286+
@Test
287+
public void testDecideAllAsync_withCallbackAndOptions() throws Exception {
288+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
289+
mockOptimizely,
290+
TEST_USER_ID,
291+
testAttributes
292+
));
293+
294+
userContext.decideAllAsync(TEST_OPTIONS, mockDecisionsCallback);
295+
296+
verify(userContext).coreDecideAllAsync(TEST_OPTIONS, mockDecisionsCallback);
297+
}
298+
299+
@Test
300+
public void testDecideAllAsync_withCallbackOnly() throws Exception {
301+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
302+
mockOptimizely,
303+
TEST_USER_ID,
304+
testAttributes
305+
));
306+
307+
userContext.decideAllAsync(mockDecisionsCallback);
308+
309+
verify(userContext).coreDecideAllAsync(Collections.emptyList(), mockDecisionsCallback);
310+
}
311+
312+
// ===========================================
313+
// Tests for Blocking Async Decide Methods
314+
// ===========================================
315+
316+
@Test
317+
public void testDecideAsync_blocking_withOptions() throws Exception {
318+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
319+
mockOptimizely,
320+
TEST_USER_ID,
321+
testAttributes
322+
));
323+
324+
doReturn(mockDecision).when(userContext).coreDecide(any(), any());
325+
326+
OptimizelyDecision result = userContext.decideAsync(TEST_FLAG_KEY, TEST_OPTIONS);
327+
328+
verify(userContext).coreDecide(TEST_FLAG_KEY, TEST_OPTIONS);
329+
assertEquals(mockDecision, result);
330+
}
331+
332+
@Test
333+
public void testDecideAsync_blocking_withoutOptions() throws Exception {
334+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
335+
mockOptimizely,
336+
TEST_USER_ID,
337+
testAttributes
338+
));
339+
340+
doReturn(mockDecision).when(userContext).coreDecide(any(), any());
341+
342+
OptimizelyDecision result = userContext.decideAsync(TEST_FLAG_KEY);
343+
344+
verify(userContext).coreDecide(TEST_FLAG_KEY, Collections.emptyList());
345+
assertEquals(mockDecision, result);
346+
}
347+
348+
@Test
349+
public void testDecideForKeysAsync_blocking_withOptions() throws Exception {
350+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
351+
mockOptimizely,
352+
TEST_USER_ID,
353+
testAttributes
354+
));
355+
356+
doReturn(mockDecisionsMap).when(userContext).coreDecideForKeys(any(), any());
357+
358+
Map<String, OptimizelyDecision> result = userContext.decideForKeysAsync(TEST_FLAG_KEYS, TEST_OPTIONS);
359+
360+
verify(userContext).coreDecideForKeys(TEST_FLAG_KEYS, TEST_OPTIONS);
361+
assertEquals(mockDecisionsMap, result);
362+
}
363+
364+
@Test
365+
public void testDecideForKeysAsync_blocking_withoutOptions() throws Exception {
366+
// Create spy of the actual class
367+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
368+
mockOptimizely,
369+
TEST_USER_ID,
370+
testAttributes
371+
));
372+
373+
doReturn(mockDecisionsMap).when(userContext).coreDecideForKeys(any(), any());
374+
375+
Map<String, OptimizelyDecision> result = userContext.decideForKeysAsync(TEST_FLAG_KEYS);
376+
377+
verify(userContext).coreDecideForKeys(TEST_FLAG_KEYS, Collections.emptyList());
378+
assertEquals(mockDecisionsMap, result);
379+
}
380+
381+
@Test
382+
public void testDecideAllAsync_blocking_withOptions() throws Exception {
383+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
384+
mockOptimizely,
385+
TEST_USER_ID,
386+
testAttributes
387+
));
388+
389+
doReturn(mockDecisionsMap).when(userContext).coreDecideAll(any());
390+
391+
Map<String, OptimizelyDecision> result = userContext.decideAllAsync(TEST_OPTIONS);
392+
393+
verify(userContext).coreDecideAll(TEST_OPTIONS);
394+
assertEquals(mockDecisionsMap, result);
395+
}
396+
397+
@Test
398+
public void testDecideAllAsync_blocking_withoutOptions() throws Exception {
399+
OptimizelyUserContextAndroid userContext = spy(new OptimizelyUserContextAndroid(
400+
mockOptimizely,
401+
TEST_USER_ID,
402+
testAttributes
403+
));
404+
405+
doReturn(mockDecisionsMap).when(userContext).coreDecideAll(any());
406+
407+
Map<String, OptimizelyDecision> result = userContext.decideAllAsync();
408+
409+
verify(userContext).coreDecideAll(Collections.emptyList());
410+
assertEquals(mockDecisionsMap, result);
411+
}
412+
230413
}

0 commit comments

Comments
 (0)