Back to Repositories

Testing DrawableResource State Management in Glide

This test suite validates the DrawableResource class functionality in Glide’s drawable handling system. It ensures proper resource management, drawable state handling, and null safety for Android drawable resources.

Test Coverage Overview

The test suite provides comprehensive coverage of DrawableResource behavior and edge cases.

  • Tests drawable instance creation and management
  • Validates constant state handling and new drawable generation
  • Covers null state scenarios
  • Verifies proper exception handling for null inputs

Implementation Analysis

The testing approach utilizes JUnit and Robolectric for Android drawable testing.

Implements mock objects with Mockito to simulate drawable behavior and verify interactions. Uses a TestDrawable inner class to validate inheritance scenarios and type-specific handling.

Technical Details

Testing infrastructure includes:

  • Robolectric test runner with SDK configuration
  • Mockito for mocking drawable objects and constant states
  • JUnit assertions and Truth assertion library
  • Custom TestDrawable implementation for type testing

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Proper test setup and resource initialization in @Before methods
  • Comprehensive edge case coverage including null handling
  • Clear test method naming conveying test purpose
  • Effective use of mocking to isolate test scenarios

bumptech/glide

library/test/src/test/java/com/bumptech/glide/load/resource/drawable/DrawableResourceTest.java

            
package com.bumptech.glide.load.resource.drawable;

import static com.bumptech.glide.RobolectricConstants.ROBOLECTRIC_SDK;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import com.bumptech.glide.load.resource.gif.GifDrawable;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(sdk = ROBOLECTRIC_SDK)
public class DrawableResourceTest {
  private TestDrawable drawable;
  private DrawableResource<TestDrawable> resource;

  @Before
  public void setUp() {
    drawable = mock(TestDrawable.class);
    resource =
        new DrawableResource<TestDrawable>(drawable) {
          @NonNull
          @Override
          public Class<TestDrawable> getResourceClass() {
            return TestDrawable.class;
          }

          @Override
          public int getSize() {
            return 0;
          }

          @Override
          public void recycle() {}
        };
  }

  @Test
  public void testDoesNotReturnOriginalDrawableOnGet() {
    when(drawable.getConstantState()).thenReturn(mock(Drawable.ConstantState.class));
    assertNotEquals(drawable, resource.get());
  }

  @SuppressWarnings("TruthIncompatibleType")
  @Test
  public void testReturnsNewDrawableOnGet() {
    GifDrawable expected = mock(GifDrawable.class);
    Drawable.ConstantState constantState = mock(Drawable.ConstantState.class);
    when(constantState.newDrawable()).thenReturn(expected);
    when(drawable.getConstantState()).thenReturn(constantState);

    assertThat(resource.get())
        .isEqualTo(/* expected: TestDrawable, actual: GifDrawable */ expected);

    verify(drawable).getConstantState();
    verify(constantState).newDrawable();
  }

  @Test
  public void get_withNullState_returnsOriginalDrawable() {
    when(drawable.getConstantState()).thenReturn(null);

    assertThat(resource.get()).isEqualTo(drawable);
  }

  @Test(expected = NullPointerException.class)
  public void testThrowsIfDrawableIsNull() {
    new DrawableResource<TestDrawable>(null) {
      @NonNull
      @Override
      public Class<TestDrawable> getResourceClass() {
        return TestDrawable.class;
      }

      @Override
      public int getSize() {
        return 0;
      }

      @Override
      public void recycle() {}
    };
  }

  /** Just to have a type to test with which is not directly Drawable */
  private static class TestDrawable extends Drawable {
    @Override
    public void draw(@NonNull Canvas canvas) {}

    @Override
    public void setAlpha(int alpha) {}

    @Override
    public void setColorFilter(ColorFilter cf) {}

    @Override
    public int getOpacity() {
      return 0;
    }
  }
}