使用Robolectric进行单元测试ActiveAndroid模型

时间:2015-04-10 02:03:40

标签: android unit-testing robolectric android-context activeandroid

我正在为我的一些模型使用ActiveAndroid,我想开始对我的工作进行单元测试。不幸的是,我遇到了一大堆错误,即无法使用正确的上下文初始化ActiveAndroid。

ActiveAndroid未被利用:

ActiveAndroid.initialize(上下文)

我试图通过以下方式初始化上下文:

  1. 有一个扩展Application的存根类,并使用它来初始化db。

    private class TestApp extends com.activeandroid.app.Application{
       @Override
       public void onCreate() {
         super.onCreate();
         initialiseDB(getDatabaseName());
       }
    
       protected String getDatabaseName() {
         return "sad";
       }
    
       private void initialiseDB(String dbName) {
          ActiveAndroid.initialize(this); 
       }
    }
    
  2. 这失败了,因为类为.getPackageName()和.getApplicationContext()返回null,这两个都由initialize内部使用。

    我也尝试过使用ShadowContextWrapper,但我可能错了。我是这样做的:

        ShadowContextWrapper shadowContextWrapper = new ShadowContextWrapper();
        shadowContextWrapper.setApplicationName("appName");
        shadowContextWrapper.setPackageName("package");
        Context context = shadowContextWrapper.getApplicationContext();
    

    此方法在ShadowContextWrapper.java:52中使用NPE失败 Robolectric的哪一部分。这条线本身:

        Context applicationContext = this.realContextWrapper.getBaseContext().getApplicationContext();
    

    我正在使用AS 1.2,robolectric3.0和activeandroid 3.1。

    以下是我正在运行的测试示例。

    @RunWith(CustomRobolectricTestRunner.class)
       public class ItemTest {
    
         public void setUp(){
    
         }
    
        @Test
        public void checkJUnitWork() {
           assertThat(true, is(true));
        }
    
        @Test
        public void testSave(){
           Item item = new Item("name", "units", 5.0, 4.5, 10.0);
           assertThat(item.getName(),is("name"));
        }
    
       public void tearDown(){
    
       }
    }
    

    我的自定义Runner如下:

    public class CustomRobolectricTestRunner extends RobolectricTestRunner {
    
    public CustomRobolectricTestRunner(Class<?> testClass)
            throws InitializationError {
        super(testClass);
        String buildVariant = (BuildConfig.FLAVOR.isEmpty()
                ? "" : BuildConfig.FLAVOR+ "/") + BuildConfig.BUILD_TYPE;
        String intermediatesPath = BuildConfig.class.getResource("")
                .toString().replace("file:", "");
        intermediatesPath = intermediatesPath
                .substring(0, intermediatesPath.indexOf("/classes"));
    
        System.setProperty("android.package",
                BuildConfig.APPLICATION_ID);
        System.setProperty("android.manifest",
                intermediatesPath + "/manifests/full/"
                        + buildVariant + "/AndroidManifest.xml");
        System.setProperty("android.resources",
                intermediatesPath + "/res/" + buildVariant);
        System.setProperty("android.assets",
                intermediatesPath + "/assets/" + buildVariant);
    
        ShadowContextWrapper shadowContextWrapper = new ShadowContextWrapper();
        shadowContextWrapper.setApplicationName("appName");
        shadowContextWrapper.setPackageName("package");
        Context context = shadowContextWrapper.getApplicationContext();
    
        ActiveAndroid.initialize(context);
    
    }
    

    }

1 个答案:

答案 0 :(得分:4)

因此,您在测试中遇到的问题是TestApp未运行。要使其运行,您需要设置测试以使用指定TestApp作为要运行的应用程序的清单。

在源树的/test目录中的某个位置设置TestApp,例如: /src/test/java/some-long-package/TestApp.java

package com.some.company;

public class TestApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ActiveAndroid.initialize(this);
    }
}

这是重要的部分

在源代码的/test树中创建一个Android清单文件。将此清单文件指定为TestApp作为应用程序。因此,在包含以下内容的/src/test/resources/TestManifest.xml路径中创建清单:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.test">

        <application android:name="com.some.company.TestApp">

    </application>
</manifest>

我建议删除CustomRobolectricTestRunner,因为默认的Robolectric 3.0测试运行器将完成你需要做的大部分工作。如果您需要测试各种构建变体,请使用@RunWith(RobolectricGradleTestRunner.class)

但是现在,按如下方式设置测试:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, manifest = "src/test/resources/TestManifest.xml", sdk = Build.VERSION_CODES.LOLLIPOP)
public class MainAppTest {

    @Test
    public void runtimeApplicationShouldBeTestApp() throws Exception {
       String actualName = RuntimeEnvironment.application.getClass().getName();
       String expectedName = TestApp.class.getName();
       assert(actualName).equals(expectedName);
    }
}

@Config(manifest= ...)位将设置Robolectric以使用测试清单和测试应用程序。上面的测试简单验证了测试中使用的应用程序上下文确实是TestApp.class 这将确保为测试正确初始化ActiveAndroid。

我同意Eugen的观点,你可能会尝试在测试中做一点点。通过应用程序测试数据库,您可以有效地创建集成测试。我建议尽可能地拆分功能。

快乐测试!