Android Espresso测试如何无需添加代码分支Mock Activity依赖的类
可行实现方案
你完全不需要在生产代码里加任何分支逻辑,以下是3种成熟的落地方案:
方案1:依赖注入框架(最适合大型项目,长期可维护)
这是大型App做测试隔离的标准方案,不需要修改任何生产代码的业务逻辑,只需要补全依赖注入声明即可:
- 给需要mock的类加注入注解,比如用Hilt的话给
MainActivity2CustomClass加@Inject构造函数 - Activity里不要直接new实例,改为字段注入:
@AndroidEntryPoint public class MainActivity2 extends AppCompatActivity { @Inject MainActivity2CustomClass mainActivity2CustomClass; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); mainActivity2CustomClass.foo(); } }
- 测试侧直接用Hilt的测试替换规则,全局或者单测试用例替换该类的实现为mock:
@HiltAndroidTest public class MainActivity2Test { @Mock MainActivity2CustomClass mockCustomClass; @BindValue MainActivity2CustomClass bindMock = mockCustomClass; @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this); @Test public void testFoo() { // 先打桩mock的行为 doNothing().when(mockCustomClass).foo(); // 启动Activity,拿到的就是mock实例 ActivityScenario.launch(MainActivity2.class); } }
优势:全局可复用,所有需要mock的类都可以通过同一套规则替换,无生产代码侵入,性能无损耗
方案2:构造方法Mock(零生产代码修改,适合不想改现有架构的场景)
用Mockito 3.5+自带的构造方法Mock能力,直接拦截Activity中new类的逻辑,返回mock实例,完全不需要动生产代码:
@Test public void testMockConstructor() { // mock所有MainActivity2CustomClass的构造调用,返回mock实例 try (MockedConstruction<MainActivity2CustomClass> mocked = mockConstruction(MainActivity2CustomClass.class, (mock, context) -> { // 自定义mock的行为 doNothing().when(mock).foo(); })) { ActivityScenario.launch(MainActivity2.class); // 验证构造方法被调用,foo方法被调用 MainActivity2CustomClass constructedInstance = mocked.constructed().get(0); verify(constructedInstance).foo(); } }
优势:零生产代码修改,适合临时给老项目加测试的场景
方案3:测试变体SourceSet替换(零侵入,成本最低)
如果你的类是public可替换的,直接在androidTest的sourceSet下创建完全相同包名类名的类,构建时测试变体优先使用test下的类:
- 在
src/androidTest/java/[你的类对应包路径]/路径下创建和生产代码完全同包名同类名的MainActivity2CustomClass - 测试构建时会优先用androidTest下的这个类替换生产的类,完全不需要改任何生产代码
优势:实现成本最低,不需要引入额外框架,适合少量类替换的场景
所有方案都不需要在生产代码中加任何测试相关的分支逻辑,完全满足大型项目的可维护性要求。
内容的提问来源于stack exchange,提问作者gmmo
相关产品推荐
相关产品推荐

