Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.d4rk.androidtutorials.java.notifications.managers;

import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;

import org.junit.Test;
import org.mockito.ArgumentCaptor;

import java.util.concurrent.TimeUnit;

/**
* Tests for {@link AppUsageNotificationsManager}.
*/
public class AppUsageNotificationsManagerTest {

@Test
public void scheduleAppUsageCheck_setsRepeatingAlarmWithThreeDayInterval() {
AlarmManager alarmManager = mock(AlarmManager.class);
Context context = mock(Context.class);
when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(alarmManager);
when(context.getApplicationContext()).thenReturn(context);

long now = System.currentTimeMillis();
AppUsageNotificationsManager manager = new AppUsageNotificationsManager(context);

Comment on lines +24 to +33

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Stub PendingIntent to avoid RuntimeException in manager test

The new unit test constructs AppUsageNotificationsManager, which immediately calls PendingIntent.getBroadcast. In the local app/src/test environment there is no Robolectric dependency, so calling this Android framework method throws RuntimeException("Stub!") and the test will crash before reaching the verification. The test should mock or stub the PendingIntent static call (or be moved to androidTest) so the suite can execute.

Useful? React with 👍 / 👎.

manager.scheduleAppUsageCheck();

ArgumentCaptor<Long> triggerCaptor = ArgumentCaptor.forClass(Long.class);
verify(alarmManager).setRepeating(
eq(AlarmManager.RTC_WAKEUP),
triggerCaptor.capture(),
eq(TimeUnit.DAYS.toMillis(3)),
any(PendingIntent.class)
);

long expectedTrigger = now + TimeUnit.DAYS.toMillis(3);
assertTrue(Math.abs(triggerCaptor.getValue() - expectedTrigger) < 1000);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.d4rk.androidtutorials.java.notifications.workers;

import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockConstruction;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.SharedPreferences;

import androidx.preference.PreferenceManager;
import androidx.work.WorkerParameters;

import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;

/**
* Tests for {@link AppUsageNotificationWorker}.
*/
public class AppUsageNotificationWorkerTest {

@Test
public void doWork_lastUsedExceedsThreshold_showsNotificationAndUpdatesTimestamp() {
Context context = mock(Context.class);
when(context.getApplicationContext()).thenReturn(context);
when(context.getString(anyInt())).thenReturn("");
NotificationManager notificationManager = mock(NotificationManager.class);
when(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager);

SharedPreferences sharedPreferences = mock(SharedPreferences.class);
SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
when(sharedPreferences.getLong(eq("lastUsed"), anyLong())).thenReturn(0L);
when(sharedPreferences.edit()).thenReturn(editor);
when(editor.putLong(anyString(), anyLong())).thenReturn(editor);

try (MockedStatic<PreferenceManager> prefManager = mockStatic(PreferenceManager.class);
MockedConstruction<NotificationChannel> ignoredChannel = mockConstruction(NotificationChannel.class)) {
Comment on lines +49 to +50

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] Import mockStatic to compile worker tests

Both test methods rely on mockStatic to stub PreferenceManager.getDefaultSharedPreferences, but the file never imports org.mockito.Mockito.mockStatic. Because the method is referenced without qualification, the test suite will not compile (cannot find symbol: method mockStatic) and ./gradlew test will fail before any tests run.

Useful? React with 👍 / 👎.

prefManager.when(() -> PreferenceManager.getDefaultSharedPreferences(context))
.thenReturn(sharedPreferences);

WorkerParameters workerParameters = mock(WorkerParameters.class);
AppUsageNotificationWorker worker = new AppUsageNotificationWorker(context, workerParameters);

worker.doWork();
}

verify(notificationManager, times(1)).notify(eq(0), any(Notification.class));

ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class);
verify(editor).putLong(eq("lastUsed"), captor.capture());
verify(editor).apply();
assertTrue(captor.getValue() > 0L);
}

@Test
public void doWork_lastUsedWithinThreshold_noNotificationButTimestampUpdated() {
Context context = mock(Context.class);
when(context.getApplicationContext()).thenReturn(context);
when(context.getString(anyInt())).thenReturn("");
NotificationManager notificationManager = mock(NotificationManager.class);
when(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager);

long lastUsed = System.currentTimeMillis();
SharedPreferences sharedPreferences = mock(SharedPreferences.class);
SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
when(sharedPreferences.getLong(eq("lastUsed"), anyLong())).thenReturn(lastUsed);
when(sharedPreferences.edit()).thenReturn(editor);
when(editor.putLong(anyString(), anyLong())).thenReturn(editor);

try (MockedStatic<PreferenceManager> prefManager = mockStatic(PreferenceManager.class);
MockedConstruction<NotificationChannel> ignoredChannel = mockConstruction(NotificationChannel.class)) {
prefManager.when(() -> PreferenceManager.getDefaultSharedPreferences(context))
.thenReturn(sharedPreferences);

WorkerParameters workerParameters = mock(WorkerParameters.class);
AppUsageNotificationWorker worker = new AppUsageNotificationWorker(context, workerParameters);

worker.doWork();
}

verify(notificationManager, never()).notify(anyInt(), any(Notification.class));

ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class);
verify(editor).putLong(eq("lastUsed"), captor.capture());
verify(editor).apply();
assertTrue(captor.getValue() >= lastUsed);
}
}

Loading