zoukankan      html  css  js  c++  java
  • 《Gradle权威指南》--Android Gradle测试

    No1:

    Android既可以用传统的JUnit测试,也可以用Android的instrument测试。

    No2:

    当我们运行测试的时候,androidTest SourceSet会被构建成一个可以安装到设备上的测试apk,这个测试apk里有很多我们写好的测试用例,它们会被执行,来测试我们的app。

    No3:

    android{
        defaultConfig{
            testApplicationId "org.flysnow.app.example121.test"
            testInstrumenttationRunner "android.test.InstrumentationTestRunner"
            testHandleProfiling true
            testFunctionalTest true
        }
    }

    testApplicationId--测试apk的包名

    testFunctionTest--是否启用功能测试

    testHandleProfiling--是否启用性能分析

    testInstrumentationRunner--运行测试使用的Instrumentation Runner

    -----------------------------------

    最后根据配置生成AndroidManifest.xml文件

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schema.android.com/apk/res/android"
        package="org.flysnow.app.example121.test">
        
        <users-sdk android:minSdkVersion="14" android:targetSdkVersion="23"/>
        <application>
            <uses-library android:name="android.test.runner"/>
        </application>
        <instrumentation android:name="android.test.InstrumentationTestRunner"
                         android:targetPackage="org.flysnow.app.example121"
                         android:handleProfiling="true"
                         android:functionalTest="true"
                         android:label="Tests for org.flysnow.app.example121"/>
    </manifest>

    targetPackage会使用被测试App的包名自动填充

    No4:

    依赖

    dependencies{
        androidTestCompile 'com.android.support:support-annotation:23.0.1'
        androidTestCompile 'com.android.support:test:runner:0.4.1'
        androidTestCompile 'com.android.support.test:rules:0.4.1'
    }

    会被编译到测试apk中,正式的apk包里没有这些jar库

    No5:

    测试apk默认是debug模式,但也可以改为release模式

    android{
        ...
        testBuildType "release"
    }

    No6:

    运行测试代码:使用./gradlew connectedCheck运行。内部步骤是:

    1)使用adnroidAndroidTest任务构建好测试应用和被测试应用,其中欧冠被测试应用又是被assembleDebug任务构建的

    2)通过install任务安装这两个应用

    3)运行我们写好的测试用例,等运行完之后,卸载两个应用

    4)最后测试的结果会被保存在build/androidTest-results目录下

    注:测试Application项目不会有被测试的apk生成,只有一个测试apk生成

    No7:

    本地单元测试--不依赖Android框架或者只有非常少的依赖,直接运行在本地开发机器上,不需要设备或模拟器

    比较常用的模拟框架有Mockito和JMock

    No8:

    针对特定的BuildType和特定的Flavor测试。每一种BuildType,每一种Flavor都有对应的测试用例存放目录

    比如:

    src/main/java/对应的是src/test/java

    src/debug/java/对应的是src/testDebug/java/

    src/google/java/对应的是src/testGoogle/java/

    No9:

    JUnit3和JUnit4的区别:

    JUnit的测试用例需要都集成junit.framework.TestCase,并且测试方法要以test为前缀。JUnit4就没有这些限制,测试方法也只需要使用@Test注解进行标注就好了

    package org.flysnow.app.example122;
    
    import org.junit.Test;
    import static org.hamcrest.CoreMatchers.is;
    import static org.junit.Assert.assertThat;
    
    public class EmailValidatorTest{
        @Test
        public void emailValidator_CorrectEmailSimple_ReturnsTrue(){
            assertThat(EmailValitor.isValidEmail("name@email.com"),is(true));
        }
        @Test
        public void emailValidator_CorrectEmailSimple_ReturnsFalse(){
            assertThat(EmailValidator.isValidEmail("name"),is(false));
        }
    }

    执行

    ./gradlew :example122:test

    测试结果在build/reports/tests目录下

    No10:

    使用Mockito框架

    dependencies{
        testCompile 'junit:junit:4.12'
        testCompile 'org.mockito:mockito-core:1.10.19'
    }
    package org.flysnow.app.example122;
    
    import android.content.Context;
    
    public class Utils{
        private Context mContext;
        
        public Utils(Context context){
            this.mContext = context;
        }
        public String getAppName(){
            return String.valueOf(mContext.getString(R.string.app_name));
        }
    }
    package org.flysnow.app.example122;
    
    import android.content.Context;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.Mock;
    import org.mockito.runners.MockitoJUnitRunner;
    import static org.hamcrest.CoreMatchers.*;
    import static org.junit.Assert.*;
    import static org.mockito.Mockito.*;
    
    @RunWith(MockitoJUnitRunner.class)
    public class UtilsTest{
        private static final String APP_NAME = "Example122";
        
        @Mock
        Context mMockContext;
        @Test
        public void readAppNameFromContext(){
            when(mMockContext.getString(R.string.app_name)).thenReturn(APP_NAME);
            
            Utils utils = new Utils(mMockContext);
            String appName = utils.getAppName();
            assertThat(appName,is(APP_NAME));
        }
    }

    1)告诉JUnit4要使用MockitlJUnitRunner

    2)模拟Context的对象mMockContext

    3)when.thenReturn逻辑,when一定要和Utils里的getAppName方法的逻辑一样,thenReturn告知模拟器期望返回的值

    4)使用./gradlew :example 122:test执行查看结果

    No11:

    Instrument测试--运行在真实的安卓物理机或模拟器上。要生成一个测试apk。下面以AndroidJUnitRunner为例

    android{
        defaultConfig{
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
            testApplicationId "con.example.app.test"
        }
    }
    
    dependencies{
        compile fileTree(dir: 'libs',include:['*.jar'])
        androidTestCompile 'com.android.support.test:runner:0.4.1'
        androidTestCompile 'com.android.support.test:rules:0.4.1'
    }
    package org.flysnow.app.example123;
    
    import android.support.test.rule.ActivityTestRule;
    import android.support.test.runner.AndroidJUnit4;
    import android.test.suitebuilder.annotation.LargeTest;
    import org.junit.Before;
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    
    @RunWith(AndroidJUnit4.class)
    @LargeTest
    public class MainActivityTest{
        @Rule
        public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);
        @Before
        public void initSomethind(){}
        @Test
        public void validSomething(){
            mActivityRule.getActivity().findViewById(android.R.id.test1).performClick();
        }
    }

    @LargeTest说明它有更高的权限

    @Rule指定规则:要测试的是MainActivity

    另外还有其他的库可以使用

    dependencies{
        androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
        androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
        androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
    }

    No12:

    测试选项配置testOptions闭包

    android{
        ...
        testOptions{
            reportDir = "$project.buildDir/example123/report"
            resultsDir = "$project.buildDir/example123/result"
            unitTests.all{
                jvmArgs '-XX:MaxPermSize=256m'
            }
        }
    }

    1)reportDir:用于配置生成测试报告的目录

    2)resultsDir:用于配置生成测试结果的目录

    3)unitTests:用于控制单元测试的执行--上面是指定启动的JVM的最大非堆内存是256M

    ---------------------------------------------

    把每个库项目的测试报告统一合并查看:android-reporting

    只需要在总的build.gradle中配置

    apply plugin: 'android-reporting'

    然后执行./gradlew deviceCheck mergeAndroidReports -continue

    -continue是在测试失败的时候,也可以继续执行其他测试用例

    No13:

    代码覆盖率--testCoverageEnabled控制菜吗覆盖率统计是否开启

    android{
        buildTypes{
            release{
                minifyEnabled true
                proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
                zipAlignEnabled true
            }
            debug{
                testCoverageEnabled = true
            }
        }
    }

    另外,要注意配置jacoco时的Android Gradle的版本号

    1)如果是1.5.0之前的版本

    android{
        jacoco{
            version = '0.6.2.201302030002'
        }
    }

    2)如果是1.5.0版本,在根项目的build.gradle里配置

    buildscript{
        repositories{
            jcenter()
        }
        dependencies{
            classpath 'org.jacoco:org.jacoco.core:0.7.4.201502262128'
        }
    }

    3)从2.0.0版本开始,不管在根项目,还是子项目都可以使用了

    运行

    ./gradlew createDebugCoverageReport,报告在build/reports/coverage下

    No14:

    Lint支持--代码、资源的优化工具--lintOptions{}闭包

    android{
        lintOptions{
            abortOnErroe true
            warningsAsErrors true
            check 'NewApi'
        }
    }

    abortOnError--boolean类型,用于配置Lint发现错误时是否退出Gradle构建

    absolutPaths--boolean类型,用于配置错误的输出里是否应该显示绝对路径,默认显示的是相对路径

    check--set集合

    android{
        lintOptions{
            check 'NewApi'
        }
    }

    注:NewApi就是一个issue id,终端输入lint --list查看所有可用id,另外,lint --show可以查看详细信息

    android{
        lintOptions{
            def checkSet = new HashSet<String>()
            checkSet.add("NewApi");
            checkSet.add("InlinedApi")
            check = checkSet
        }
    }

    缩写

    android{
        lintOptions{
            check 'InlinedApi','NewApi'
        }
    }

    checkAllWarnings--boolean类型,True表示需要检查所有警告的issue,包括那些默认被关闭的issue,false不检查

    checkReleaseBuilds--boolean类型,用于配置在release构建的过程中,Lint是否应该检查致命的错误的问题,默认true,一旦发现有‘fatal’级别的问题,release构建会被终止

    disable--用来关闭给定issue id的Lint检查,和check用法一样

    enable--用来配置哪些issue id启动lint check,和disable用法相反

    explainIssues--boolean类型,用来配置Lint检查出的错误报告是否应该包含解释说明

    htmlOutput--File类型,用于配置HTML报告输出的文件路径

    android{
        lintOptions{
            htmlOutput new File("${buildDir}/lintReports/lint-results.html")
        }
    }

    htmlReport--boolean类型,用于配置是否生成HTML报告,默认是true

    ignoreWarings--boolean类型,用于配置Lint是否忽略警告级别的检查,只检查错误级别

    lintConfig--File类型,用于指定Lint的配置文件,

    noLines--boolean类型,如果为true,error输出将不会包含源代码的行号

    quiet--boolean类型,表示是否开启安静模式,这样Lint分析的进度或者其他信息将不会显示

    severityOverrides--返回一个Map类型结果,用来获取issue的优先级。Map的key是issue id,value是优先级,包括fatal、error、warning、informational、ignore

    showAll--boolean类型,用于标记是否应该显示所有的输出

    textOutput--File类型,用于指定生成的test格式的报告的路径

    textReport--boolean类型,用于配置是否生成text报告

    warningsAdErrors--boolean类型,用于配置是否把所有的警告也当成错误处理,默认false

    xmlOutput--File类型,用于设置生成xml报告的路径

    xmlReport--boolean类型,用于控制是否生成xml格式的报告,默认true

    error、fatal、ignore、warning、informational--用来配置issue的优先级,接受的都是issue id作为其参数。error是把给定的issue强制指定为erroe这个优先级

    -------------------------

    运行./gradlew lint,默认生成报告在output/lint-results.html下

  • 相关阅读:
    汉字数组排序及如何检测汉字
    响应式web布局中iframe的自适应
    CSS3的flex布局
    关于BFC不会被浮动元素遮盖的一些解释
    趣谈unicode,ansi,utf-8,unicode big endian这些编码有什么区别(转载)
    深入seajs源码系列三
    深入seajs源码系列二
    深入seajs源码系列一
    韩国"被申遗" (转自果壳)
    Understanding delete
  • 原文地址:https://www.cnblogs.com/anni-qianqian/p/8659825.html
Copyright © 2011-2022 走看看