Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Andriod 单元测试(五)——测试Hilt组件 #182

Open
soapgu opened this issue Dec 13, 2022 · 0 comments
Open

Andriod 单元测试(五)——测试Hilt组件 #182

soapgu opened this issue Dec 13, 2022 · 0 comments
Labels
Demo Demo 安卓 安卓

Comments

@soapgu
Copy link
Owner

soapgu commented Dec 13, 2022

  • 前言

Hilt是我们选用的必备组件。
我们大多数类都是要注入到安卓对象的。所以为了以后的TDD目标做准备,把Hilt加入到单元测试是必要条件。

  • Hilt 测试准备

plugins {
    id 'com.android.application' version '7.3.0' apply false
    id 'com.android.library' version '7.3.0' apply false
     //hilt plugin
    id 'com.google.dagger.hilt.android' version '2.44.2' apply false
}

gradle升级到7.X.X以后project到build.gradle文件使用新写法,需要增加hilt插件

app的build.gradle文件

plugins {
    id 'com.android.application'
    id 'dagger.hilt.android.plugin'
}

dependencies {
    implementation "com.google.dagger:hilt-android:2.44.2"
    annotationProcessor "com.google.dagger:hilt-android-compiler:2.44.2"
    // For local unit tests
    testImplementation 'com.google.dagger:hilt-android-testing:2.44.2'
    testAnnotationProcessor 'com.google.dagger:hilt-compiler:2.44.2'
}

再写个注入对象和Module

public class SampleSingletonClass {
    public String echo(){
        return "hello singleton";
    }
}

@Module
@InstallIn(SingletonComponent.class)
public class SingletonModule {
    @Provides
    public SampleSingletonClass provideObject(){
        return new SampleSingletonClass();
    }
}

注入到MainActivity里面去

@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
    @Inject
    protected SampleSingletonClass singletonClass;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.tv_message = findViewById(R.id.tv_message);
        findViewById(R.id.button_hilt).setOnClickListener( v -> this.tv_message.setText( singletonClass.echo() ) );
    }
}

这样点击测试按钮就直接把TextView的Text改成SampleSingletonClass的输出了
虚拟器设备测试没问题。准备完毕

  • Unit Test 的hello world

按照文档来要三步走
To use Hilt in a test:

  1. Annotate the test with @HiltAndroidTest,
  2. Add the HiltAndroidRule test rule,
  3. Use HiltTestApplication for your Android Application class.

好像出师不利啊!

No instrumentation registered! Must run under a registering instrumentation.
java.lang.IllegalStateException: No instrumentation registered! Must run under a registering instrumentation.
	at androidx.test.platform.app.InstrumentationRegistry.getInstrumentation(InstrumentationRegistry.java:45)
	at androidx.test.core.app.ApplicationProvider.getApplicationContext(ApplicationProvider.java:41)
	at dagger.hilt.android.internal.testing.MarkThatRulesRanRule.<init>(MarkThatRulesRanRule.java:43)
	at dagger.hilt.android.testing.HiltAndroidRule.<init>(HiltAndroidRule.java:36)
	at com.demo.myunittest.HiltTest.<init>(HiltTest.java:22)

文档上说得不清不楚的,最后实践下来,主要要加
@RunWith(RobolectricTestRunner.class)

完成单元测试代码

@RunWith(RobolectricTestRunner.class)
@HiltAndroidTest
@Config(application = HiltTestApplication.class)
public class HiltTest {
    @Rule
    public HiltAndroidRule hiltRule = new HiltAndroidRule(this);

    @Inject
    SampleSingletonClass singletonClass;

    @Test
    public void testSingleton() {
        Assert.assertNull(singletonClass);
        hiltRule.inject();
        Assert.assertNotNull( singletonClass );
        Assert.assertEquals( "hello singleton",singletonClass.echo() );
    }
}

头铁下,如果不用测试的HiltTestApplication会怎么样
就用程序的App
@config(application = App.class)

Hilt test, com.demo.myunittest.HiltTest, cannot use a @HiltAndroidApp application but found com.demo.myunittest.App. To fix, configure the test to use HiltTestApplication or a custom Hilt test application generated with @CustomTestApplication.
java.lang.IllegalStateException: Hilt test, com.demo.myunittest.HiltTest, cannot use a @HiltAndroidApp application but found com.demo.myunittest.App. To fix, configure the test to use HiltTestApplication or a custom Hilt test application generated with @CustomTestApplication.

果然报错,报错还蛮人性化。如果要自定义就用@CustomTestApplication

  • @TestInstallIn 李代桃僵

不是所有的模块都能测试,有的需要打桩替换,这个@TestInstallIn就是专门用来移形换影的。

A Dagger module annotated with @TestInstallIn allows users to replace an existing @InstallIn module for all tests in a given source set.

一般替换的Moudule和测试代码放一起

components定义模块级别
replaces 定义别替换的模块类

@Module
@TestInstallIn(components = SingletonComponent.class,
replaces = SingletonModule.class)
public class FakeSingletonModule {
    @Provides
    public SampleSingletonClass provideObject(){
        SampleSingletonClass retValue = mock(SampleSingletonClass.class);
        when(retValue.echo()).thenReturn("mocked hilt object echo");
        return retValue;
    }
}

这样测试类看看echo改不改

    @Test
    public void testSingleton() {
        Assert.assertNull(singletonClass);
        hiltRule.inject();
        Assert.assertNotNull( singletonClass );
        Assert.assertEquals( "mocked hilt object echo",singletonClass.echo() );
    }

最后再测试一下Activity注入的桩是不是一样

    @Test
    public void testActivity(){
        try (ActivityController<MainActivity> controller = Robolectric.buildActivity(MainActivity.class)) {
            controller.setup();
            MainActivity activity = controller.get();
            Assert.assertNotNull("inject single in Activity",activity.singletonClass);
            Assert.assertEquals( "mocked hilt object echo",activity.singletonClass.echo() );
        }
    }

测试也蛮顺利,Activity是onCreated()会自动填充的。不需要调用hiltRule.inject();

  • 总结

Hilt的特别会我们配了测试组件,使用起来还是蛮方便的。demo体验下暂时没啥问题。下次可以试试真实项目的测试效果了

@soapgu soapgu added 安卓 安卓 Demo Demo labels Dec 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Demo Demo 安卓 安卓
Projects
None yet
Development

No branches or pull requests

1 participant