【问题标题】:Robolectric - Application has Singletons in setup, causing issues with testsRobolectric - 应用程序在设置中有单例,导致测试问题
【发布时间】:2016-06-07 15:59:17
【问题描述】:

我目前继承了一个代码覆盖率为零的 Android 应用程序,我的第一份工作是为它编写一些单元测试。所以我决定也以此为契机学习 Robolectric。

但是,在运行两个简单的虚拟测试时,我遇到了初始问题。

这是我的测试文件中的代码:

@Config(constants = BuildConfig.class)
@RunWith(RobolectricGradleTestRunner.class)
public class SplashActivityTest {

private SplashActivity activity;

// @Before => JUnit 4 annotation that specifies this method should run before each test is run
// Useful to do setup for objects that are needed in the test
@Before
public void setup() {
    // Convenience method to run SplashActivity through the Activity Lifecycle methods:
    // onCreate(...) => onStart() => onPostCreate(...) => onResume()
    activity = Robolectric.setupActivity(SplashActivity.class);
}

// @Test => JUnit 4 annotation specifying this is a test to be run
// Checking that the UI gets setup correctly
@Test
public void dummy() {
  String test = "POP!";

    assertTrue("POP!",
            test.equals("POP!"));
}

@Test
public void dummyTwo() {

    String test = "POP!!";

    assertTrue("POP!!",
            test.equals("POP!!"));
}

}

问题是活动扩展了另一个名为 baseactivity 的类,并且在这个类中使用了一个自定义应用程序类。

在这个自定义应用程序类中,Picasso 使用以下代码创建为单例:

picasso = new Picasso.Builder(getApplicationContext()).downloader(new OkHttpDownloader(picassoClient)).build();
    Picasso.setSingletonInstance(picasso);

当我运行测试时,出现以下错误:

java.lang.IllegalStateException:单例实例已经存在。 在 com.squareup.picasso.Picasso.setSingletonInstance(Picasso.java:677)

所以看起来应用程序类被创建了两次,每次测试一次,因为一次测试运行良好。所以我假设我的测试模式在这里是错误的?任何人都可以帮助我正确的模式吗?与单元测试一样,我只想测试有限的功能,所以我不确定我所做的是否正确。

编辑:我尝试设置一个“模拟”应用程序类并让 Robolectric 使用它,但它似乎仍然使用真正的应用程序类。

所以在 test/java 我有以下类:

public class TestMyApplication extends MyApplication
        implements TestLifecycleApplication {

    @Override
    public void onCreate() {
        super.onCreate();
        initPicasso();
    }

    @Override
    protected void initPicasso() {
        //nothing to do
    }

    @Override public void beforeTest(Method method) {
    }

    @Override public void prepareTest(Object test) {
    }

    @Override public void afterTest(Method method) {
    }
}

如您所见,它扩展了我的主应用程序中的 MyApplication 类,并且我还在 initPicasso 方法中添加了 @Override 以尝试阻止它被调用,但是当我运行测试时,我仍然收到错误Picasso Singleton 被设置为第二次测试。

所以当我运行我的测试类时,它仍然会进入我的主应用程序中的 Application 类,当单元测试的范围应该被限制时,为什么 Robolectric 会这样做?

我也试过这个:

@Config(constants = BuildConfig.class, application = TestMyApplication.class)

但是当我尝试这个并运行测试类时,我收到一条错误消息,说它找不到 TestMyApplication,所以对于 Robolectric 为何不使用我的模拟应用程序类,这是一个令人头疼的问题。

【问题讨论】:

  • 如果您尝试了这种方法,那么您改变了什么?它应该为每个测试创建应用程序 - 单元测试应该是独立且可重复的
  • 如果你完全删除了毕加索的初始化测试。我通常做什么我抽象毕加索或至少是静态性质,并在必要时在测试中模拟它(通常是因为我的覆盖率总是接近 90%)
  • 啊抱歉,你能在你的应用程序测试中覆盖它并让它为空,所以没有实例化毕加索

标签: java android unit-testing robolectric


【解决方案1】:

为了让它工作,我必须创建以下扩展 RobolectricGradleTestRunner 的类并强制它使用 TestMyApplication 类。

public class TestRunner extends RobolectricGradleTestRunner {

    public TestRunner(final Class<?> testClass) throws InitializationError {
        super(testClass);
    }

    @Override
    protected Class<? extends TestLifecycle> getTestLifecycleClass() {
        return MyTestLifecycle.class;
    }

    public static class MyTestLifecycle extends DefaultTestLifecycle {
        @Override
        public Application createApplication(final Method method, final AndroidManifest appManifest, final Config appConfig) {
            // run tests under our TestApplication
            return new TestMyApplication();
        }
    }

}

然后在 TestMyApplication 类中我必须重写 initPicasso 方法:

@Override protected void initPicasso(){
        //do nothing
    }

只有在这样做之后,Robolectric 才最终跳过主 MyApplication.java 类中的 initPicasso。

【讨论】:

  • 它仍然应该开箱即用 :) 如果你可以分享代码,我可能会修复它,至少我愿意 :)
  • 有机会我会试着整理一些样本并发送给你,我不能分享这个特定的代码。
  • 请保留风味并在其中反映应用 ID 更改
【解决方案2】:

在 Robolectric 3.4.2 中,在测试工作中使用自定义应用程序类:

public class MyApplication extends Application {

    protected void initPicasso() {
        // do Picasso initialization
    }

}

public class TestMyApplication extends MyApplication {

    @Override
    protected void initPicasso() {
        //nothing to do
    }

}

只需在您的测试类中添加一个 Config 注释:

@Config(constants = BuildConfig.class, application = TestMyApplication.class)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-07
    • 1970-01-01
    • 2011-04-23
    • 2015-02-24
    • 2011-04-12
    • 2015-04-15
    相关资源
    最近更新 更多