Back to Repositories

Validating ModelLoader Registry Implementation in Glide

This test suite validates the ModelLoaderRegistry class in Glide, which manages model loader registration and retrieval. It ensures proper handling of model loader registration, validation of model instances, and appropriate error handling when no suitable loaders are found.

Test Coverage Overview

The test suite provides comprehensive coverage of ModelLoaderRegistry functionality including:
  • Validation of unregistered model loader scenarios
  • Testing model loader registration and handling
  • Verification of multiple model loader interactions
  • Edge case handling for incompatible model instances
Integration points include the FactoryPools thread-safe list implementation and mock model loader interactions.

Implementation Analysis

The testing approach utilizes JUnit with Robolectric for Android environment simulation. The suite employs Mockito for mocking model loaders and implements a systematic pattern of test cases that progress from basic error conditions to complex multi-loader scenarios.

Framework-specific features include @RunWith(RobolectricTestRunner.class) for Android context simulation and Truth assertions for enhanced verification capabilities.

Technical Details

Testing tools and configuration:
  • JUnit 4 for test execution
  • Robolectric for Android runtime simulation
  • Mockito for mock object creation
  • Google Truth for fluent assertions
  • Custom mock model loader factory implementation

Best Practices Demonstrated

The test suite exemplifies several testing best practices:
  • Proper test isolation using @Before setup
  • Systematic error case validation
  • Clear test method naming conventions
  • Efficient mock object reuse
  • Comprehensive assertion messages
  • Helper methods for common setup operations

bumptech/glide

library/test/src/test/java/com/bumptech/glide/load/model/ModelLoaderRegistryTest.java

            
package com.bumptech.glide.load.model;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import androidx.annotation.NonNull;
import com.bumptech.glide.Registry.NoModelLoaderAvailableException;
import com.bumptech.glide.util.pool.FactoryPools;
import org.junit.Before;
import org.junit.Test;
import org.junit.function.ThrowingRunnable;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;

@RunWith(RobolectricTestRunner.class)
public class ModelLoaderRegistryTest {
  private static final String MOCK_MODEL_LOADER_NAME = "MockModelLoader";

  private ModelLoaderRegistry registry;

  @Before
  public void setUp() {
    registry = new ModelLoaderRegistry(FactoryPools.<Throwable>threadSafeList());
  }

  @Test
  public void getModelLoaders_withNoRegisteredModelLoader_throws() {
    final Object model = new Object();
    NoModelLoaderAvailableException thrown =
        assertThrows(
            NoModelLoaderAvailableException.class,
            new ThrowingRunnable() {
              @Override
              public void run() {
                registry.getModelLoaders(model);
              }
            });

    assertThat(thrown)
        .hasMessageThat()
        .contains(
            "Failed to find any ModelLoaders registered for model class: " + model.getClass());
  }

  @Test
  public void getModelLoaders_withRegisteredModelLoader_thatDoesNotHandleModelInstance_throws() {
    final Object model = new Object();
    final ModelLoader<Object, Object> modelLoader = mockModelLoader();
    when(modelLoader.handles(model)).thenReturn(false);
    appendModelLoader(modelLoader);

    NoModelLoaderAvailableException thrown =
        assertThrows(
            NoModelLoaderAvailableException.class,
            new ThrowingRunnable() {
              @Override
              public void run() {
                registry.getModelLoaders(model);
              }
            });

    assertThat(thrown)
        .hasMessageThat()
        .contains(
            "Found ModelLoaders for model class: [MockModelLoader], but none that handle this"
                + " specific model instance: java.lang.Object");
  }

  @Test
  public void getModelLoaders_withRegisteredModelLoader_handlesModel_returnsModelLoader() {
    final Object model = new Object();
    final ModelLoader<Object, Object> modelLoader = mockModelLoader();
    when(modelLoader.handles(model)).thenReturn(true);
    appendModelLoader(modelLoader);

    assertThat(registry.getModelLoaders(model)).containsExactly(modelLoader);
  }

  @Test
  public void
      getModelLoaders_withRegisteredModelLoaders_onlyOneHandlesModel_returnsHandlingModelLoader() {
    final Object model = new Object();

    ModelLoader<Object, Object> handlingModelLoader = mockModelLoader();
    when(handlingModelLoader.handles(model)).thenReturn(true);
    appendModelLoader(handlingModelLoader);

    ModelLoader<Object, Object> notHandlingModelLoader = mockModelLoader();
    when(notHandlingModelLoader.handles(model)).thenReturn(false);
    appendModelLoader(notHandlingModelLoader);

    assertThat(registry.getModelLoaders(model)).containsExactly(handlingModelLoader);
  }

  private void appendModelLoader(final ModelLoader<Object, Object> modelLoader) {
    registry.append(
        Object.class,
        Object.class,
        new ModelLoaderFactory<Object, Object>() {
          @NonNull
          @Override
          public ModelLoader<Object, Object> build(@NonNull MultiModelLoaderFactory multiFactory) {
            return modelLoader;
          }

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

  @SuppressWarnings("unchecked")
  private static ModelLoader<Object, Object> mockModelLoader() {
    return mock(ModelLoader.class, MOCK_MODEL_LOADER_NAME);
  }
}