自定义带Bitmap输入、AsyncTask回调的库的自动化测试及Mockito咨询
好问题!咱们一步步来解决你的疑问:
问题1:这类测试的可行性与实践方式
这类测试完全可行,而且是Android库开发中非常通用的实践——属于集成测试或功能测试的范畴,专门用来验证库在各种边界条件(异常输入、网络异常等)下的表现,确保鲁棒性。
关于测试位置:完全可以在库的测试目录中独立完成,不需要单独创建应用。Android Studio为库模块提供了两类测试目录,按需选择:
src/test/java:本地单元测试,运行在JVM上,速度快,适合测试纯逻辑,但无法直接模拟Android框架的真实运行环境(比如AsyncTask的异步调度)src/androidTest/java:Instrumented测试,运行在真机或模拟器上,可以完整模拟Android系统环境、网络状态,适合测试依赖Android API的逻辑(比如你的AsyncTask执行、回调触发)
问题2:测试接口回调的示例代码(含Mockito用法)
首先需要在库的build.gradle中添加必要的测试依赖:
dependencies { // 本地单元测试依赖 testImplementation 'org.mockito:mockito-core:4.8.1' testImplementation 'junit:junit:4.13.2' // Instrumented测试依赖(如果需要真机/模拟器测试) androidTestImplementation 'org.mockito:mockito-android:4.8.1' androidTestImplementation 'androidx.test.ext:junit:1.1.5' }
假设你的库核心类是ImageInfoManager,回调接口定义如下:
public interface ImageInfoCallback { void onSuccess(String imageInfo); void onFailure(Exception e); }
下面分两种场景给出测试示例:
场景1:本地单元测试(模拟回调与逻辑)
本地测试中,我们用Mockito模拟回调接口和Bitmap,同时抽离AsyncTask的核心逻辑(避免依赖Android环境):
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import android.graphics.Bitmap; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) public class ImageInfoManagerTest { @Mock private ImageInfoCallback mockCallback; // 模拟回调对象 @Mock private Bitmap mockBitmap; // 模拟Bitmap输入 private ImageInfoManager manager = new ImageInfoManager(); // 测试有效Bitmap输入的成功回调 @Test public void testFetchImageInfo_ValidBitmap_TriggersSuccess() { // 执行测试方法 manager.fetchImageInfo(mockBitmap, mockCallback); // 模拟AsyncTask执行完成并返回结果(这里假设你把网络请求逻辑抽成了可调用的方法) String mockInfo = "Sample: Landscape, 1920x1080"; manager.onFetchCompleted(mockInfo); // 手动触发成功回调(根据你的库逻辑调整) // 验证回调的onSuccess被正确调用 verify(mockCallback).onSuccess(mockInfo); // 确保onFailure没有被调用 verify(mockCallback, never()).onFailure(any(Exception.class)); } // 测试空Bitmap输入的失败回调 @Test public void testFetchImageInfo_NullBitmap_TriggersFailure() { // 传入空Bitmap执行方法 manager.fetchImageInfo(null, mockCallback); // 模拟空值校验失败的异常 Exception error = new IllegalArgumentException("Bitmap cannot be null"); manager.onFetchFailed(error); // 验证失败回调被触发 verify(mockCallback).onFailure(error); verify(mockCallback, never()).onSuccess(anyString()); } // 测试网络异常的失败回调 @Test public void testFetchImageInfo_NetworkError_TriggersFailure() { manager.fetchImageInfo(mockBitmap, mockCallback); // 模拟网络请求失败 Exception networkError = new RuntimeException("Network unavailable"); manager.onFetchFailed(networkError); verify(mockCallback).onFailure(networkError); verify(mockCallback, never()).onSuccess(anyString()); } }
场景2:Instrumented测试(模拟真实网络状态)
如果需要测试真实Android环境下的网络禁用场景,可以用Instrumented测试配合Mockito模拟ConnectivityManager:
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; import android.content.Context; import android.graphics.Bitmap; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.mockito.Mockito.*; @RunWith(AndroidJUnit4.class) public class ImageInfoManagerInstrumentedTest { @Mock private ImageInfoCallback mockCallback; private Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); private ImageInfoManager manager = new ImageInfoManager(appContext); // 测试禁用网络时的回调 @Test public void testFetchImageInfo_NoNetwork_TriggersFailure() throws InterruptedException { // 模拟无网络状态 ConnectivityManager mockCm = mock(ConnectivityManager.class); when(mockCm.getActiveNetworkCapabilities()).thenReturn(null); // 替换系统的ConnectivityManager(如果你的库依赖它判断网络) // 注意:实际项目中可能需要用依赖注入来替换,避免直接依赖系统服务 // 创建一个真实的Bitmap作为输入 Bitmap testBitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); manager.fetchImageInfo(testBitmap, mockCallback); // 用CountDownLatch等待异步回调触发 CountDownLatch latch = new CountDownLatch(1); doAnswer(invocation -> { latch.countDown(); return null; }).when(mockCallback).onFailure(any(Exception.class)); // 等待最多5秒,确保回调执行完成 latch.await(5, TimeUnit.SECONDS); // 验证失败回调被调用 verify(mockCallback).onFailure(any(Exception.class)); } }
关键Mockito用法提示
@Mock:自动创建模拟对象,不用手动newverify(mock).method(args):验证模拟对象的方法是否被调用(以及调用次数、参数是否正确)when(mock.method()).thenReturn(result):给模拟对象的方法设定返回值doAnswer():用来监听回调方法的调用,配合CountDownLatch处理异步逻辑
内容的提问来源于stack exchange,提问作者Sebastien Ferrand
相关产品推荐
相关产品推荐

