Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/184.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 单元测试领域&x2B;匕首2,带机械分子&;莫基托_Android_Unit Testing_Realm_Robolectric_Dagger 2 - Fatal编程技术网

Android 单元测试领域&x2B;匕首2,带机械分子&;莫基托

Android 单元测试领域&x2B;匕首2,带机械分子&;莫基托,android,unit-testing,realm,robolectric,dagger-2,Android,Unit Testing,Realm,Robolectric,Dagger 2,所以我正在做这个小项目,它使用Dagger2进行依赖注入,并将Realm作为数据库 我正在使用Robolectric和Mockito(使用Powermock)对其进行单元测试。从以前的研究(和很多痛苦)中,我意识到测试领域相当困难,但在过去已经完成了 现在,我的项目的设置和结构与上面链接的项目非常相似 当我运行单元测试时,所有测试都通过了,只有一个测试给了我一个非常神秘的消息,如下所示: java.lang.NullPointerException at org.robolectric.inte

所以我正在做这个小项目,它使用Dagger2进行依赖注入,并将Realm作为数据库

我正在使用Robolectric和Mockito(使用Powermock)对其进行单元测试。从以前的研究(和很多痛苦)中,我意识到测试领域相当困难,但在过去已经完成了

现在,我的项目的设置和结构与上面链接的项目非常相似

当我运行单元测试时,所有测试都通过了,只有一个测试给了我一个非常神秘的消息,如下所示:

java.lang.NullPointerException
at org.robolectric.internal.ShadowExtractor.extract(ShadowExtractor.java:5)
at org.robolectric.Shadows.shadowOf(Shadows.java:1190)
at org.robolectric.shadows.CoreShadowsAdapter.getMainLooper(CoreShadowsAdapter.java:37)
at org.robolectric.util.ComponentController.<init>(ComponentController.java:31)
at org.robolectric.util.ComponentController.<init>(ComponentController.java:23)
at org.robolectric.util.ActivityController.<init>(ActivityController.java:40)
at org.robolectric.util.ActivityController.of(ActivityController.java:32)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:82)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:78)
at org.robolectric.Robolectric.setupActivity(Robolectric.java:86)
at uk.co.placona.tradesafe.view.EditActivityTest.ActivityShouldNotBeNull(EditActivityTest.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl
该活动存在,并在启动时将TradeRepository注入其中

有问题的活动可以与代码的其余部分一起找到。我已经试着调试了大约3天,但没有成功。我创建的其他每一个单元测试都可以很好地工作,除了活动使用的任何单元测试,这让我觉得我可能遗漏了一些非常明显的东西


我很乐意在这里澄清任何问题。非常感谢

静态是邪恶的,powermock是邪恶的:)

我认为你应该离开你的班级。您不需要它,因为在应用程序的生命周期中只有一个CustomApplication对象

您应该按如下方式修改代码:

在CustomApplication.java中,创建应用程序组件,在字段变量中设置,然后注入

private ApplicationComponent applicationComponent;

public void setup(){
        getOrCreateApplicationComponent().inject(this);
        databaseRealm.setup();
        stethoDebug.setup(this);
    }

public ApplicationComponent getOrCreateApplicationComponent() {
        if (applicationComponent == null) {
            applicationComponent = DaggerApplicationComponent.builder()
                    .applicationContextModule(new ApplicationContextModule(this))
                    .repositoryModule(new RepositoryModule())
                    .build();
        }

        return applicationComponent;
    }
在CreateActivity、EditActivity和MainActivity的onCreate方法中,Injector被替换为

    ((CustomApplication) getApplication())
            .getOrCreateApplicationComponent()
            .inject(this);
在RepositoryModule中,我们将使用Dagger2将依赖项注入构造函数中,这样我们就不需要手动注入上下文和DatabaseRealm

@Provides
@Singleton
public TradeRepository provideTradeRepository(DatabaseRealm databaseRealm) {
    return new TradeRepositoryImpl(databaseRealm);
}

@Provides
@Singleton
public DatabaseRealm provideDatabaseRealm(Context context) {
    return new DatabaseRealm(context);
}
然后在DatabaseRealm中,我们添加一个以上下文为参数的构造函数

Context mContext;

RealmConfiguration realmConfiguration;

public DatabaseRealm(Context context) {
    mContext = context;
}
在TradeRepositoryImpl中,添加了一个带有databaseRealm的构造函数

DatabaseRealm databaseRealm;

public TradeRepositoryImpl(DatabaseRealm databaseRealm) {
    this.databaseRealm = databaseRealm;
}
对于RepositoryTestModule,我们添加databaseRealm作为参数:

@Provides
@Singleton
public TradeRepository provideTradeRepository(DatabaseRealm databaseRealm) {
    return isMocked ? mock(TradeRepository.class) : new TradeRepositoryImpl(databaseRealm);
}
在TestCustomApplication中,我们覆盖getOrCreateApplicationComponent

@Override
    public ApplicationComponent getOrCreateApplicationComponent() {
        return DaggerApplicationComponentTest.builder()
                .applicationContextModuleTest(new ApplicationContextModuleTest())
                .repositoryModuleTest(new RepositoryModuleTest(false))
                .build();
    }
现在,对于您的每个测试,我们使用RobolectricGradleTestRunner运行它们,并添加TestCustomApplication.class作为应用程序标记

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21, application = TestCustomApplication.class)
当我们需要向测试中注入依赖项时,我们将如下注入:

@Before
public void setupDagger() {
    DaggerApplicationComponentTest.builder()
            .applicationContextModuleTest(new ApplicationContextModuleTest())
            .repositoryModuleTest(new RepositoryModuleTest(false))
            .build().inject(this);
}
EditActivityTest中仍然存在NullPointerException,因为此行:

loadTrade(intent.getExtras().getString("ID"));

要么检查意图是否为非空,要么在测试中提供一个意图。

静态是邪恶的,powermock是邪恶的:)

我认为你应该离开你的班级。您不需要它,因为在应用程序的生命周期中只有一个CustomApplication对象

您应该按如下方式修改代码:

在CustomApplication.java中,创建应用程序组件,在字段变量中设置,然后注入

private ApplicationComponent applicationComponent;

public void setup(){
        getOrCreateApplicationComponent().inject(this);
        databaseRealm.setup();
        stethoDebug.setup(this);
    }

public ApplicationComponent getOrCreateApplicationComponent() {
        if (applicationComponent == null) {
            applicationComponent = DaggerApplicationComponent.builder()
                    .applicationContextModule(new ApplicationContextModule(this))
                    .repositoryModule(new RepositoryModule())
                    .build();
        }

        return applicationComponent;
    }
在CreateActivity、EditActivity和MainActivity的onCreate方法中,Injector被替换为

    ((CustomApplication) getApplication())
            .getOrCreateApplicationComponent()
            .inject(this);
在RepositoryModule中,我们将使用Dagger2将依赖项注入构造函数中,这样我们就不需要手动注入上下文和DatabaseRealm

@Provides
@Singleton
public TradeRepository provideTradeRepository(DatabaseRealm databaseRealm) {
    return new TradeRepositoryImpl(databaseRealm);
}

@Provides
@Singleton
public DatabaseRealm provideDatabaseRealm(Context context) {
    return new DatabaseRealm(context);
}
然后在DatabaseRealm中,我们添加一个以上下文为参数的构造函数

Context mContext;

RealmConfiguration realmConfiguration;

public DatabaseRealm(Context context) {
    mContext = context;
}
在TradeRepositoryImpl中,添加了一个带有databaseRealm的构造函数

DatabaseRealm databaseRealm;

public TradeRepositoryImpl(DatabaseRealm databaseRealm) {
    this.databaseRealm = databaseRealm;
}
对于RepositoryTestModule,我们添加databaseRealm作为参数:

@Provides
@Singleton
public TradeRepository provideTradeRepository(DatabaseRealm databaseRealm) {
    return isMocked ? mock(TradeRepository.class) : new TradeRepositoryImpl(databaseRealm);
}
在TestCustomApplication中,我们覆盖getOrCreateApplicationComponent

@Override
    public ApplicationComponent getOrCreateApplicationComponent() {
        return DaggerApplicationComponentTest.builder()
                .applicationContextModuleTest(new ApplicationContextModuleTest())
                .repositoryModuleTest(new RepositoryModuleTest(false))
                .build();
    }
现在,对于您的每个测试,我们使用RobolectricGradleTestRunner运行它们,并添加TestCustomApplication.class作为应用程序标记

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21, application = TestCustomApplication.class)
当我们需要向测试中注入依赖项时,我们将如下注入:

@Before
public void setupDagger() {
    DaggerApplicationComponentTest.builder()
            .applicationContextModuleTest(new ApplicationContextModuleTest())
            .repositoryModuleTest(new RepositoryModuleTest(false))
            .build().inject(this);
}
EditActivityTest中仍然存在NullPointerException,因为此行:

loadTrade(intent.getExtras().getString("ID"));

要么检查意图是否为非空,要么在测试中提供一个。

查看您的测试类,我没有看到您使用任何Robolectric测试运行程序

您必须使用
RobolectricGradleTestRunner
RobolectricTestRunner
触发Robolectric功能,以加载清单、解析资源、创建主循环器等

如果您不使用它们,您可能可以在设置中使用自己的代码来实现它,但这不是通常的方式,我不确定这里有多少人可以向您解释如何实现它


同样,RobolectricPowerMock都在修改java
ClassLoader
。这就是为什么很难(也许不可能)让他们一起工作的原因。因此,请检查@Steve answer如何修改您的代码,以删除测试的必要性。

查看您的测试类,我没有看到您使用任何Robolectric测试运行程序

您必须使用
RobolectricGradleTestRunner
RobolectricTestRunner
触发Robolectric功能,以加载清单、解析资源、创建主循环器等

如果您不使用它们,您可能可以在设置中使用自己的代码来实现它,但这不是通常的方式,我不确定这里有多少人可以向您解释如何实现它


同样,RobolectricPowerMock都在修改java
ClassLoader
。这就是为什么很难(也许不可能)让他们一起工作的原因。因此,请检查@Steve answer如何修改您的代码以删除测试的必要性。

您是否使用
PowerMock
运行它?是的,正如您在这里看到的:是的,已经检查过了。“PowerMock”总是很棘手是的,这正是我发现的。看到一些人建议不要使用它,我想现在我真的需要它。你是否使用
PowerMock
运行它?是的,正如你在这里看到的:是的,已经检查过了。“PowerMock”总是很棘手是的,这正是我发现的。看到一些人建议不要使用它,我想在这一点上我真的需要它。我通常创建
Test
,它将由Robolectric自动加载,以避免
定制测试应用程序