gpt4 book ai didi

android - 如何使用 Dagger 2.0 在单元测试中覆盖模块/依赖项?

转载 作者:IT王子 更新时间:2023-10-28 23:40:31 29 4
gpt4 key购买 nike

我有一个 simple Android activity有一个单一的依赖。我将依赖项注入(inject)到 Activity 的 onCreate 中,如下所示:

Dagger_HelloComponent.builder()
.helloModule(new HelloModule(this))
.build()
.initialize(this);

在我的 ActivityUnitTestCase 中,我想用 Mockito 模拟覆盖依赖项。我假设我需要使用提供模拟的特定于测试的模块,但我不知道如何将此模块添加到对象图中。

在 Dagger 1.x 中,这显然是通过 something like this 完成的。 :

@Before
public void setUp() {
ObjectGraph.create(new TestModule()).inject(this);
}

Dagger 2.0 相当于什么?

你可以看到我的项目和它的单元测试here on GitHub .

最佳答案

这可能是一种适当支持测试模块覆盖的解决方法,但它允许使用测试模块覆盖生产模块。下面的代码 fragment 显示了当您只有一个组件和一个模块时的简单情况,但这应该适用于任何情况。它需要大量的样板和代码重复,因此请注意这一点。我相信将来会有更好的方法来实现这一点。

我还创建了一个 project with examples for Espresso and Robolectric .此答案基于项目中包含的代码。

解决方案需要两件事:

  • @Component
  • 提供额外的 setter
  • 测试组件必须扩展生产组件

假设我们有一个简单的Application,如下所示:

public class App extends Application {

private AppComponent mAppComponent;

@Override
public void onCreate() {
super.onCreate();
mAppComponent = DaggerApp_AppComponent.create();
}

public AppComponent component() {
return mAppComponent;
}

@Singleton
@Component(modules = StringHolderModule.class)
public interface AppComponent {

void inject(MainActivity activity);
}

@Module
public static class StringHolderModule {

@Provides
StringHolder provideString() {
return new StringHolder("Release string");
}
}
}

我们必须向 App 类添加额外的方法。这允许我们替换生产组件。

/**
* Visible only for testing purposes.
*/
// @VisibleForTesting
public void setTestComponent(AppComponent appComponent) {
mAppComponent = appComponent;
}

如您所见,StringHolder 对象包含“释放字符串”值。这个对象被注入(inject)到 MainActivity

public class MainActivity extends ActionBarActivity {

@Inject
StringHolder mStringHolder;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((App) getApplication()).component().inject(this);
}
}

在我们的测试中,我们希望为 StringHolder 提供“测试字符串”。我们必须在创建 MainActivity 之前在 App 类中设置测试组件 - 因为 StringHolder 被注入(inject)到 onCreate回调。

在 Dagger v2.0.0 中,组件可以扩展其他接口(interface)。我们可以利用它来创建我们的 TestAppComponent,它扩展 AppComponent

@Component(modules = TestStringHolderModule.class)
interface TestAppComponent extends AppComponent {

}

现在我们可以定义我们的测试模块,例如TestStringHolderModule。最后一步是使用之前在 App 类中添加的 setter 方法设置测试组件。在创建 Activity 之前执行此操作很重要。

((App) application).setTestComponent(mTestAppComponent);

浓缩咖啡

对于 Espresso,我创建了自定义 ActivityTestRule,它允许在创建 Activity 之前交换组件。您可以找到 DaggerActivityTestRule here 的代码.

Espresso sample 测试:

@RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityEspressoTest {

public static final String TEST_STRING = "Test string";

private TestAppComponent mTestAppComponent;

@Rule
public ActivityTestRule<MainActivity> mActivityRule =
new DaggerActivityTestRule<>(MainActivity.class, new OnBeforeActivityLaunchedListener<MainActivity>() {
@Override
public void beforeActivityLaunched(@NonNull Application application, @NonNull MainActivity activity) {
mTestAppComponent = DaggerMainActivityEspressoTest_TestAppComponent.create();
((App) application).setTestComponent(mTestAppComponent);
}
});

@Component(modules = TestStringHolderModule.class)
interface TestAppComponent extends AppComponent {

}

@Module
static class TestStringHolderModule {

@Provides
StringHolder provideString() {
return new StringHolder(TEST_STRING);
}
}

@Test
public void checkSomething() {
// given
...

// when
onView(...)

// then
onView(...)
.check(...);
}
}

机器人电动

借助 RuntimeEnvironment.application,使用 Robolectric 变得更加容易。

使用 Robolectric 进行样本测试:

@RunWith(RobolectricGradleTestRunner.class)
@Config(emulateSdk = 21, reportSdk = 21, constants = BuildConfig.class)
public class MainActivityRobolectricTest {

public static final String TEST_STRING = "Test string";

@Before
public void setTestComponent() {
AppComponent appComponent = DaggerMainActivityRobolectricTest_TestAppComponent.create();
((App) RuntimeEnvironment.application).setTestComponent(appComponent);
}

@Component(modules = TestStringHolderModule.class)
interface TestAppComponent extends AppComponent {

}

@Module
static class TestStringHolderModule {

@Provides
StringHolder provideString() {
return new StringHolder(TEST_STRING);
}
}

@Test
public void checkSomething() {
// given
MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);

// when
...

// then
assertThat(...)
}
}

关于android - 如何使用 Dagger 2.0 在单元测试中覆盖模块/依赖项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26939340/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com