Android测试框架Robolectric和Espresso的集成和使用


Android测试框架Robolectric和Espresso的集成和使用

Robolectric跑测试的时候并不需要将app安装到手机上,它能模拟Android的环境,并且测试运行的时间较短。
Espresso运行测试的时候需要安装app,并且运行的时间比较长,这更像是一种集成测试。

集成

依赖

    testCompile "org.mockito:mockito-core:1.+"
    testCompile "org.robolectric:shadows-multidex:3.0"
    testCompile 'junit:junit:4.12'
    testCompile 'org.robolectric:robolectric:3.3.2'

    //比较unitTest结果是能给出具体的不同点
    testCompile group: 'net.javacrumbs.json-unit', name: 'json-unit', version: '1.16.0'

//    androidTestCompile 'com.android.support:support-annotations:24.0.0'
    androidTestCompile ('com.android.support.test:runner:0.5', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    androidTestCompile ('com.android.support.test:rules:0.5', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })

    // Optional -- Hamcrest library
    androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
    // Optional -- UI testing with Espresso
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })

defaultConfig 中增加

    defaultConfig {
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        
    }

testOptions 在android{}中

    testOptions {
        unitTests.returnDefaultValues = true
        unitTests.all {
            beforeTest {
                def testClassDir = buildDir.getAbsolutePath() + "/intermediates/classes/test/debug"
                copy {
                    from(android.sourceSets.test.java.srcDirs) {
                        exclude '**/*.java'
                    }
                    into(testClassDir)
                }
            }
        }
    }

集成查看覆盖率工具jacoco

apply plugin: 'jacoco'
jacoco {
    toolVersion = "0.7.1.201405082137"
}

def coverageSourceDirs = [
        '../hall/src/main/java'
]

task jacocoTestReport(type: JacocoReport, dependsOn: "testDebugUnitTest") {
    group = "Reporting"

    description = "Generate Jacoco coverage reports"

    classDirectories = fileTree(
            dir: '../hall/build/intermediates/classes/debug',
            excludes: ['**/R.class',
                       '**/R$*.class',
                       '**/*$ViewInjector*.*',
                       '**/BuildConfig.*',
                       '**/Manifest*.*']
    )

    additionalSourceDirs = files(coverageSourceDirs)
    sourceDirectories = files(coverageSourceDirs)
    executionData = files('../hall/build/jacoco/testDebugUnitTest.exec')

    reports {
        xml.enabled = true
        html.enabled = true
    }
}

开始写测试代码

单元测试

SimpleTest.class
普通的Junit单元测试无法 对Android的数据库,SharedPreferences以及Assets文件的读取等进行测试。Robolectric能模拟Android环境,让这些单元测试变的很简单。

public class SimpleTest extends RoboBase{
    Application application;
    HallConfigManager mHallConfigManager;
    HallDbManager mHallDbManager;

    AppBean appBean;

    //单元测试开始,需要的用到的变量在此初始化
    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);//初始化Mockit
        application = RuntimeEnvironment.application;
        mHallConfigManager = HallConfigManager.getInstance();
        mHallDbManager = HallDbManager.getInstance();
        //需要mock的类初始化
        appBean = Mockito.mock(AppBean.class);
    }

    //sharedPreferences测试
    @Test
    public void sharedPreferencesTest() throws Exception{
        mHallConfigManager.setQQ("10086");
        Assert.assertEquals("10086", mHallConfigManager.getQQ());
    }

    //数据库测试
    @Test
    public void dbTest() throws Exception{
        AppBean appBean = new AppBean();
        appBean.gamePackageName = "com.uc108.test";
        mHallDbManager.replaceAppBean(appBean);
        AppBean appTemp = mHallDbManager.getAppBean("com.uc108.test");
        Assert.assertEquals("com.uc108.test", appTemp.gamePackageName);
    }

    //这条目前测试在AndroidStudio3.0上会运行失败,建议使用AndroidStudio2.2
    //读取assets目录下的文件测试
    @Test
    public void assetsTest() throws  Exception{
        String str = PackageUtils.getAssetsString("defaultlocation.json");
        Assert.assertEquals(str, "abc");
    }

    //mock测试,单元测试的过程中,可能会调用外部的方法A,为了让方法A返回值可控,这个时候你需要使用mock
    @Test
    public void mockTest() throws Exception{
        appBean.setGameName("abc");
        when(appBean.getGameName()).thenReturn("cde");
        Assert.assertEquals("cde", appBean.getGameName());
    }
}

defaultlocation.json

{
    "ProvinceName":"",
    "CityName":"",
    "DistrictName":""
}

测试结果:
测试通过 sharedPreferencesTest,dbTest,mockTest
测试未通过assetsTest

初次运行依赖Robolectric的测试的时候,由于网络的原因,速度会特别慢,这个时候我们需要如下操作:把Robolectric下载依赖的地址 指向国内的源
MyRobolectricTestRunner.class

public class MyRobolectricTestRunner extends RobolectricTestRunner {
    /**
     * Creates a runner to run {@code testClass}. Looks in your working directory for your AndroidManifest.xml file
     * and res directory by default. Use the {@link Config} annotation to configure.
     *
     * @param testClass the test class to be run
     * @throws InitializationError if junit says so
     */
    public MyRobolectricTestRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
        RoboSettings.setMavenRepositoryId("alimaven");
        RoboSettings.setMavenRepositoryUrl("http://maven.aliyun.com/nexus/content/groups/public/");
    }
}

RobApplication.class

public class RobApplication extends HallApplication {

}

Espresso UI集成测试

这个测试需要把apk安装到手机后才能运行测试。

GameSearchActivityTest.class

@RunWith(AndroidJUnit4.class)
@LargeTest
public class GameSearchActivityTest {
    //设置的测试的Activity
    @Rule
    public ActivityTestRule<GameSearchActivity> mActivityRule = new ActivityTestRule<>(
            GameSearchActivity.class, true, true);

    @Before
    public void setUp() throws Exception {
        Thread.sleep(2000);
    }

    @Test
    public void onCreate() throws Exception {

    }

    @Test
    public void onSearch() throws Exception {
        //在输入框中输入doudizhu
        onView(withId(R.id.search_et)).perform(typeText("doudizhu"), closeSoftKeyboard());
        //点击搜索按钮
        onView(withId(R.id.search_iv)).perform(click());

        //匹配search_game_result_lv ListView中tv_name游戏标题为“斗地主”item进行点击
        onData(allOf(instanceOf(AppBean.class), ItemMatcher.withName("斗地主")))
                .inAdapterView(withId(R.id.search_game_result_lv))
                .onChildView(withId(R.id.tv_name))
                .perform(click());
    }


    public static class ItemMatcher {
        public static Matcher<Object> withName(final String name) {
            return new BoundedMatcher<Object,AppBean>(AppBean.class) {
                @Override
                public void describeTo(org.hamcrest.Description description) {
                    description.appendText("item mathcher");
                }

                @Override
                protected boolean matchesSafely(AppBean item) {
                    if(item != null && !TextUtils.isEmpty(item.getGameName()) && item.getGameName().contains(name)) {
                        return true;
                    }
                    return false;
                }
            };
        }
    }

Android测试框架可以使用@SmallTest,@MediumTest和@LargeTest 来标注测试方法,这些分类划分主要是根据测试访问数据的位置,如本地,SD卡,网络,下表为通常划分测试等级的基本方法:

FeatureSmallMediumLarge
Network accessNolocalhost onlyYes
DatabaseNoYesYes
File system accessNoYesYes
Use external systemsNoDiscouragedYes
Multiple threadsNoYesYes
Sleep statementsNoYesYes
System propertiesNoYesYes
Time limit (seconds)60300900+
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值