我有一个使用Dagger 2进行依赖注入的Android应用。我还使用最新的gradle构建工具,它允许构建变体进行单元测试,并使用一个用于仪器测试。我在我的应用程序中使用java.util.Random
,我想模仿它进行测试。我测试的课程不使用任何Android内容,因此他们只是常规的Java课程。
在我的主要代码中,我在扩展Component
类的类中定义了Application
,但在单元测试中,我没有使用Application
。我尝试定义测试Module
和Component
,但Dagger不会生成Component
。我还尝试使用我在应用程序中定义的Component
并在构建时交换Module
,但应用程序Component
没有inject
Random
1}}我的测试类的方法。如何为测试提供public class PipeGameApplication extends Application {
private PipeGame pipeGame;
@Singleton
@Component(modules = PipeGameModule.class)
public interface PipeGame {
void inject(BoardFragment boardFragment);
void inject(ConveyorFragment conveyorFragment);
}
@Override
public void onCreate() {
super.onCreate();
pipeGame = DaggerPipeGameApplication_PipeGame.create();
}
public PipeGame component() {
return pipeGame;
}
}
的模拟实现?
以下是一些示例代码:
应用:
@Module
public class PipeGameModule {
@Provides
@Singleton
Random provideRandom() {
return new Random();
}
}
模块:
public class BaseModelTest {
PipeGameTest pipeGameTest;
@Singleton
@Component(modules = PipeGameTestModule.class)
public interface PipeGameTest {
void inject(BoardModelTest boardModelTest);
void inject(ConveyorModelTest conveyorModelTest);
}
@Before
public void setUp() {
pipeGameTest = DaggerBaseModelTest_PipeGameTest.create(); // Doesn't work
}
public PipeGameTest component() {
return pipeGameTest;
}
}
测试的基类:
public class BaseModelTest {
PipeGameApplication.PipeGame pipeGameTest;
// This works if I make the test module extend
// the prod module, but it can't inject my test classes
@Before
public void setUp() {
pipeGameTest = DaggerPipeGameApplication_PipeGame.builder().pipeGameModule(new PipeGameModuleTest()).build();
}
public PipeGameApplication.PipeGame component() {
return pipeGameTest;
}
}
或:
@Module
public class PipeGameTestModule {
@Provides
@Singleton
Random provideRandom() {
return mock(Random.class);
}
}
测试模块:
lmwine <- lm(quality~fixed.acidity+volatile.acidity+citric.acid+residual.sugar+chlorides+
free.sulfur.dioxide+total.sulfur.dioxide+density+pH+sulphates+alcohol,data=wineq)
summary(lm)
答案 0 :(得分:25)
目前无法使用Dagger 2(从v2.0.0开始),但没有一些解决方法。你可以阅读它here。
有关可能的解决方法的更多信息:
答案 1 :(得分:6)
你说:“你已经击中了头上的钉子:
应用程序的Component没有我的测试类的注入方法
因此,为了解决这个问题,我们可以制作一个Application类的测试版本。然后我们可以拥有您模块的测试版本。为了使它们全部在测试中运行,我们可以使用Robolectric。
1)创建Application类的测试版
public class TestPipeGameApp extends PipeGameApp {
private PipeGameModule pipeGameModule;
@Override protected PipeGameModule getPipeGameModule() {
if (pipeGameModule == null) {
return super.pipeGameModule();
}
return pipeGameModule;
}
public void setPipeGameModule(PipeGameModule pipeGameModule) {
this.pipeGameModule = pipeGameModule;
initComponent();
}}
2)您的原始Application类需要 initComponent()和 pipeGameModule()方法
public class PipeGameApp extends Application {
protected void initComponent() {
DaggerPipeGameComponent.builder()
.pipeGameModule(getPipeGameModule())
.build();
}
protected PipeGameModule pipeGameModule() {
return new PipeGameModule(this);
}}
3)您的PipeGameTestModule应该使用构造函数扩展生产模块:
public class PipeGameTestModule extends PipeGameModule {
public PipeGameTestModule(Application app) {
super(app);
}}
4)现在,在junit test的 setup()方法中,在测试应用上设置此测试模块:
@Before
public void setup() {
TestPipeGameApp app = (TestPipeGameApp) RuntimeEnvironment.application;
PipeGameTestModule module = new PipeGameTestModule(app);
app.setPipeGameModule(module);
}
现在,您可以根据自己的需要自定义测试模块。
答案 2 :(得分:2)
在我看来,你可以从不同的角度来看待这个问题。您可以轻松地对您的类进行单元测试,不依赖于Dagger测试的构造类,并将其模拟的依赖项注入其中。
我的意思是说,在测试设置中,您可以:
我们不需要测试是否正确地注入依赖项,因为Dagger在编译期间验证依赖图的正确性。因此编译失败将报告任何此类错误。这就是为什么在设置方法中手动创建测试类应该是可接受的原因。
使用被测试类中的构造函数注入依赖项的代码示例:
public class BoardModelTest {
private BoardModel boardModel;
private Random random;
@Before
public void setUp() {
random = mock(Random.class);
boardModel = new BoardModel(random);
}
@Test
...
}
public class BoardModel {
private Random random;
@Inject
public BoardModel(Random random) {
this.random = random;
}
...
}
使用测试类中的字段注入依赖项的代码示例(如果BoardModel
由框架构造):
public class BoardModelTest {
private BoardModel boardModel;
private Random random;
@Before
public void setUp() {
random = mock(Random.class);
boardModel = new BoardModel();
boardModel.random = random;
}
@Test
...
}
public class BoardModel {
@Inject
Random random;
public BoardModel() {}
...
}
答案 3 :(得分:1)
如果您在Android上使用dagger2,则可以使用app flavor来提供模拟资源。
在这里查看模拟测试中的风味演示(没有匕首): https://www.youtube.com/watch?v=vdasFFfXKOY
这个代码库有一个例子: https://github.com/googlecodelabs/android-testing
在 /src/prod/com/yourcompany/Component.java 中 您提供生产组件。
在 /src/mock/com/yourcompany/Component.java 中 你提供嘲弄的组件。
这允许您使用或不使用模拟来创建应用程序的构建。 它还允许并行开发(一个团队的后端,另一个团队的前端应用程序),你可以模拟直到api方法可用。
我的gradle命令的外观(它是一个Makefile):
install_mock:
./gradlew installMockDebug
install:
./gradlew installProdDebug
test_unit:
./gradlew testMockDebugUnitTest
test_integration_mock:
./gradlew connectedMockDebugAndroidTest
test_integration_prod:
./gradlew connectedProdDebugAndroidTest
答案 4 :(得分:0)
我实际上遇到了同样的问题,并找到了一个非常简单的解决方案。 这不是我认为最好的解决方案,但它会解决您的问题。
在您的app模块中创建一个类似的类:
public class ActivityTest<T extends ViewModelBase> {
@Inject
public T vm;
}
然后,在AppComponent中添加:
void inject(ActivityTest<LoginFragmentVM> activityTest);
然后你就可以在你的测试课中注入它了。
public class HelloWorldEspressoTest extends ActivityTest<LoginFragmentVM> {
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule(MainActivity.class);
@Test
public void listGoesOverTheFold() throws InterruptedException {
App.getComponent().inject(this);
vm.email.set("1234");
closeSoftKeyboard();
}
}