Back to Repositories

Testing Stream Asset Path Fetching Operations in Glide

This test suite evaluates the StreamAssetPathFetcher class in the Glide library, focusing on asset loading functionality. It verifies proper handling of input stream operations, resource cleanup, and cancellation behaviors when fetching assets through Android’s AssetManager.

Test Coverage Overview

The test suite provides comprehensive coverage of the StreamAssetPathFetcher’s core operations.

Key areas tested include:
  • Input stream opening and data loading
  • Resource cleanup handling
  • Cancellation behavior
  • Error handling for unloaded data scenarios
The tests specifically verify interactions with Android’s AssetManager and proper stream management.

Implementation Analysis

The testing approach utilizes Mockito for dependency isolation and behavior verification. The implementation employs the Robolectric testing framework for Android-specific components, with careful attention to mock initialization and verification patterns.

The test structure follows JUnit conventions with @Before setup and individual @Test methods for specific scenarios, leveraging Mockito’s powerful verification capabilities.

Technical Details

Testing tools and configuration:
  • JUnit 4 test framework
  • Mockito for mocking and verification
  • Robolectric for Android environment simulation
  • Custom SDK configuration using ROBOLECTRIC_SDK
  • MockitoAnnotations for automatic mock initialization

Best Practices Demonstrated

The test suite exemplifies several testing best practices including proper test isolation, clear test method naming, and comprehensive scenario coverage.

Notable practices include:
  • Systematic setup of test dependencies
  • Explicit verification of method calls and interactions
  • Proper resource management testing
  • Clear separation of test scenarios
  • Effective use of mocking to isolate system under test

bumptech/glide

library/test/src/test/java/com/bumptech/glide/load/data/StreamAssetPathFetcherTest.java

            
package com.bumptech.glide.load.data;

import static com.bumptech.glide.RobolectricConstants.ROBOLECTRIC_SDK;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.res.AssetManager;
import com.bumptech.glide.Priority;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(sdk = ROBOLECTRIC_SDK)
public class StreamAssetPathFetcherTest {
  @Mock private AssetManager assetManager;
  @Mock private InputStream expected;
  @Mock private DataFetcher.DataCallback<InputStream> callback;

  private StreamAssetPathFetcher fetcher;

  @Before
  public void setUp() throws IOException {
    MockitoAnnotations.initMocks(this);
    String assetPath = "/some/asset/path";
    fetcher = new StreamAssetPathFetcher(assetManager, assetPath);
    when(assetManager.open(eq(assetPath))).thenReturn(expected);
  }

  @Test
  public void testOpensInputStreamForPathWithAssetManager() throws Exception {
    fetcher.loadData(Priority.NORMAL, callback);
    verify(callback).onDataReady(eq(expected));
  }

  @Test
  public void testClosesOpenedInputStreamOnCleanup() throws Exception {
    fetcher.loadData(Priority.NORMAL, callback);
    fetcher.cleanup();

    verify(expected).close();
  }

  @Test
  public void testDoesNothingOnCleanupIfNoDataLoaded() throws IOException {
    fetcher.cleanup();
    verify(expected, never()).close();
  }

  @Test
  public void testDoesNothingOnCancel() throws Exception {
    fetcher.loadData(Priority.NORMAL, callback);
    fetcher.cancel();
    verify(expected, never()).close();
  }
}