Back to Repositories

Testing Animated Image Resource Loading in Glide Framework

This test suite validates Glide’s capability to load and decode animated WebP and AVIF images from Android resources into AnimatedImageDrawable objects. It ensures proper handling of animated image formats across different Android platform versions.

Test Coverage Overview

The test suite provides comprehensive coverage for animated image loading functionality in Glide:

  • Resource ID-based loading of animated WebP files
  • Resource ID-based loading of animated AVIF files
  • URI-based loading of animated WebP resources
  • URI-based loading of animated AVIF resources
  • Platform version compatibility checks

Implementation Analysis

The testing approach utilizes JUnit4 with AndroidJUnit4 runner for Android-specific testing. It implements version-specific testing logic using Build.VERSION checks and employs Glide’s custom testing utilities like ConcurrencyHelper for asynchronous operations.

The tests use both direct resource loading and URI-based approaches to verify the same functionality through different input methods.

Technical Details

Key technical components include:

  • JUnit4 test framework with AndroidJUnit4 runner
  • Mockito for test initialization
  • Custom TearDownGlide rule for cleanup
  • ConcurrencyHelper for handling async operations
  • ContentResolver for URI-based resource access
  • Platform version constants for feature detection

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Proper test isolation using @Before and @Rule
  • Platform version checking with assumeTrue
  • Multiple input method verification
  • Clear test method naming conventions
  • Explicit type checking with assertThat
  • Resource cleanup handling

bumptech/glide

instrumentation/src/androidTest/java/com/bumptech/glide/LoadAnimatedImageResourceTest.java

            
package com.bumptech.glide;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeTrue;

import android.content.ContentResolver;
import android.content.Context;
import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.bumptech.glide.test.GlideApp;
import com.bumptech.glide.test.ResourceIds;
import com.bumptech.glide.testutil.ConcurrencyHelper;
import com.bumptech.glide.testutil.TearDownGlide;
import java.io.IOException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;

/**
 * Tests that Glide is able to load animated images (WebP and AVIF) stored in resources and loaded
 * as {@link android.graphics.drawable.AnimatedImageDrawable}s when the underlying Android platform
 * supports it.
 */
@RunWith(AndroidJUnit4.class)
public class LoadAnimatedImageResourceTest {
  @Rule public final TearDownGlide tearDownGlide = new TearDownGlide();
  private final ConcurrencyHelper concurrency = new ConcurrencyHelper();

  private Context context;

  private static final boolean IS_ANIMATED_WEBP_SUPPORTED =
      Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
  private static final boolean IS_ANIMATED_AVIF_SUPPORTED =
      Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;

  @Before
  public void setUp() throws IOException {
    MockitoAnnotations.initMocks(this);
    context = ApplicationProvider.getApplicationContext();
  }

  @Test
  public void loadAnimatedImageResourceId_fromInt_decodesAnimatedImageDrawable_Webp() {
    assumeTrue(IS_ANIMATED_WEBP_SUPPORTED);
    Drawable frame =
        concurrency.get(Glide.with(context).load(ResourceIds.raw.animated_webp).submit());

    assertThat(frame).isNotNull();
    assertThat(frame).isInstanceOf(AnimatedImageDrawable.class);
  }

  @Test
  public void loadAnimatedImageResourceId_fromInt_decodesAnimatedImageDrawable_Avif() {
    assumeTrue(IS_ANIMATED_AVIF_SUPPORTED);
    Drawable frame =
        concurrency.get(Glide.with(context).load(ResourceIds.raw.animated_avif).submit());

    assertThat(frame).isNotNull();
    assertThat(frame).isInstanceOf(AnimatedImageDrawable.class);
  }

  @Test
  public void loadAnimatedImageUri_fromId_decodesAnimatedImageDrawable_Webp() {
    assumeTrue(IS_ANIMATED_WEBP_SUPPORTED);
    Uri uri =
        new Uri.Builder()
            .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
            .authority(context.getPackageName())
            .path(String.valueOf(ResourceIds.raw.animated_webp))
            .build();

    Drawable frame = concurrency.get(GlideApp.with(context).load(uri).submit());

    assertThat(frame).isNotNull();
    assertThat(frame).isInstanceOf(AnimatedImageDrawable.class);
  }

  @Test
  public void loadAnimatedImageUri_fromId_decodesAnimatedImageDrawable_Avif() {
    assumeTrue(IS_ANIMATED_AVIF_SUPPORTED);
    Uri uri =
        new Uri.Builder()
            .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
            .authority(context.getPackageName())
            .path(String.valueOf(ResourceIds.raw.animated_avif))
            .build();

    Drawable frame = concurrency.get(GlideApp.with(context).load(uri).submit());

    assertThat(frame).isNotNull();
    assertThat(frame).isInstanceOf(AnimatedImageDrawable.class);
  }
}