Back to Repositories

Testing NotificationTarget Bitmap Handling in Glide

This test suite validates the NotificationTarget class in Glide, which handles setting bitmaps on Android notifications. It ensures proper handling of notification updates, bitmap settings, and parameter validation for the notification target implementation.

Test Coverage Overview

The test suite provides comprehensive coverage of NotificationTarget functionality including:

  • Bitmap setting on RemoteViews
  • Notification manager updates
  • Parameter validation and null checks
  • Edge cases for constructor parameters

Implementation Analysis

The testing approach utilizes Robolectric for Android framework simulation and Mockito for mocking dependencies. The tests follow a structured pattern with setUp initialization and specific test cases for each functionality aspect. Custom shadow implementation is used to verify notification updates.

Technical Details

  • Testing Framework: JUnit with Robolectric
  • Mocking: Mockito
  • Custom Shadows: UpdateShadowNotificationManager
  • Test Environment: Robolectric SDK configuration
  • Key Components: NotificationManager, RemoteViews, Bitmap handling

Best Practices Demonstrated

The test suite demonstrates several testing best practices:

  • Proper test setup and tear down
  • Isolation of Android framework dependencies
  • Explicit exception testing
  • Clear test method naming
  • Comprehensive validation of component interactions

bumptech/glide

library/test/src/test/java/com/bumptech/glide/request/target/NotificationTargetTest.java

            
package com.bumptech.glide.request.target;

import static com.bumptech.glide.RobolectricConstants.ROBOLECTRIC_SDK;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.widget.RemoteViews;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowNotificationManager;

@RunWith(RobolectricTestRunner.class)
@Config(sdk = ROBOLECTRIC_SDK, shadows = NotificationTargetTest.UpdateShadowNotificationManager.class)
public class NotificationTargetTest {
  private UpdateShadowNotificationManager shadowManager;
  private RemoteViews remoteViews;
  private int viewId;
  private Notification notification;
  private int notificationId;
  private String notificationTag;
  private NotificationTarget target;

  @Before
  public void setUp() {
    NotificationManager notificationManager =
        (NotificationManager)
            ApplicationProvider.getApplicationContext()
                .getSystemService(Context.NOTIFICATION_SERVICE);
    shadowManager = Shadow.extract(notificationManager);

    remoteViews = mock(RemoteViews.class);
    viewId = 123;
    notification = mock(Notification.class);
    notificationId = 456;
    notificationTag = "tag";

    target =
        new NotificationTarget(
            ApplicationProvider.getApplicationContext(),
            100 /*width*/,
            100 /*height*/,
            viewId,
            remoteViews,
            notification,
            notificationId,
            notificationTag);
  }

  @Test
  public void testSetsBitmapOnRemoteViewsWithGivenImageIdOnResourceReady() {
    Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
    target.onResourceReady(bitmap, null /*glideAnimation*/);
    verify(remoteViews).setImageViewBitmap(eq(viewId), eq(bitmap));
  }

  @Test
  public void updatesNotificationManagerWithNotificationIdAndNotificationOnResourceReady() {
    target.onResourceReady(
        Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888), null
        /*glideAnimation*/ );

    assertEquals(notificationId, shadowManager.updatedNotificationId);
    assertEquals(notificationTag, shadowManager.updatedNotificationTag);
    assertEquals(notification, shadowManager.updatedNotification);
  }

  @Test(expected = NullPointerException.class)
  public void testThrowsIfContextIsNull() {
    new NotificationTarget(
        null /*context*/,
        100 /*width*/,
        100 /*height*/,
        123 /*viewId*/,
        mock(RemoteViews.class),
        mock(Notification.class),
        456 /*notificationId*/,
        "tag" /*notificationTag*/);
  }

  @Test(expected = NullPointerException.class)
  public void testThrowsIfNotificationIsNull() {
    new NotificationTarget(
        ApplicationProvider.getApplicationContext(),
        100 /*width*/,
        100 /*height*/,
        123 /*viewId*/,
        mock(RemoteViews.class),
        null /*notification*/,
        456 /*notificationId*/,
        "tag" /*notificationTag*/);
  }

  @Test(expected = NullPointerException.class)
  public void testThrowsIfRemoteViewsIsNull() {
    new NotificationTarget(
        ApplicationProvider.getApplicationContext(),
        100 /*width*/,
        100 /*height*/,
        123 /*viewId*/,
        null /*remoteViews*/,
        mock(Notification.class),
        456 /*notificationId*/,
        "tag" /*notificationTag*/);
  }

  @Implements(NotificationManager.class)
  public static class UpdateShadowNotificationManager extends ShadowNotificationManager {
    int updatedNotificationId;
    String updatedNotificationTag;
    Notification updatedNotification;

    @Implementation
    @Override
    public void notify(String notificationTag, int notificationId, Notification notification) {
      updatedNotificationTag = notificationTag;
      updatedNotificationId = notificationId;
      updatedNotification = notification;
    }
  }
}