单元测试 运行android_android studio 运行所有单元测试 - CSDN
  • 1. 前言 在Android开发中,如果对一个简单的功能,每次修改代码都重新运行到...2. 添加单元测试支持 在AndroidStudio项目中,如果是新版本的AndroidStudio中新建的,会自动添加了单元测试的支持,如果旧项目,没有...

    1. 前言

        在Android开发中,如果对一个简单的功能,每次修改代码都重新运行到设备中进行测试,会浪费大量时间,降低开发工作效率。如果使用单元测试,编写单元测试类,执行测试单元测试类就可以对某些功能进行测试,大大提升了开发工作效率。

    2. 添加单元测试支持

        在AndroidStudio项目中,如果是新版本的AndroidStudio中新建的,会自动添加了单元测试的支持,如果旧项目,没有添加单元测试支持,需要手动进行配置。

    2.1 添加单元测试依赖包

        在程序模块下面的build.gradle中需要引入的依赖包:
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    • testImplementation-引入的依赖是java unit单元测试,是运行在当前电脑的jvm上的单元测试;
    • androidTestImplementation-引入的依赖是Android单元测试,是运行在Android环境的单元测试。

    2.2 添加测试代码目录

        如果AndroidStudio当前项目视图为Android,需要切换为Project视图,在程序模块下面的src目录下添加androidTest/java(Android单元测试,运行在Android环境的单元测试)和test/java(JUnit单元测试,运行在当前电脑的jvm上的单元测试),然后在里面添加包名和测试类。

    • androidTest/java(Android单元测试,运行在当前电脑的jvm上的单元测试,执行测试的时候需要Android连接设备,速度比较慢,适合需要调用Android api的单元测试)
    • test/java(JUnit单元测试,用来放不需要Android依赖的单元测试类,运行在当前电脑的jvm上的单元测试,速度快,适合只是对java代码功能进行单元测试)

    2 添加单元测试类

    2.1 手动编写单元测试类

    2.1.1 androidTest测试类

        androidTest测试类适用于需要依赖Android api的单元测试,需要连接Android设备才能进行测试。新建的androidTest java类需要添加@RunWith(AndroidJUnit4.class)注解,类的方法如果是测试入口方法需要添加@Test注解。
    示例代码:
    package com.xiaoying.untitestdemo;
    
    import android.content.Context;
    import android.content.pm.ApplicationInfo;
    import android.content.pm.PackageManager;
    import android.os.Bundle;
    import android.support.test.InstrumentationRegistry;
    
    import org.junit.Before;
    import org.junit.Test;
    
    import static org.junit.Assert.assertEquals;
    
    /**
     * Created by yinglovezhuzhu@gmail.com on 2018/5/13.
     */
    public class MainActivityTest {
    
        private Context mTargetContext;
    
        @Before
        public void setUp() throws Exception {
            mTargetContext = InstrumentationRegistry.getTargetContext();
        }
    
        @Test
        public void onCreate() {
            try {
                ApplicationInfo applicationInfo = mTargetContext.getPackageManager().getApplicationInfo(mTargetContext.getPackageName(), PackageManager.GET_META_DATA);
                Bundle metaData = applicationInfo.metaData;
                String data = metaData.getString("com.xiaoying.TEST");
    
                assertEquals("1234567890", data);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    2.1.2 test测试类

        test测试类适用于纯java的单元测试,运行于当前设备的jvm环境中,无需Android设备即可测试。新建test java类,类的方法如果是测试入口方法需要添加@Test注解。
    代码示例:
    package com.xiaoying.untitestdemo;
    
    import org.junit.Before;
    import org.junit.Test;
    
    import static org.junit.Assert.*;
    
    /**
     * Created by yinglovezhuzhu@gmail.com on 2018/5/13.
     */
    public class UtilsTest {
    
        @Before
        public void setUp() throws Exception {
    
        }
    
        @Test
        public void isEmpty() {
    
            assertEquals(true, Utils.isEmpty(""));
        }
    }

    2.1.3 测试类中的setUp方法

        在测试类中的setUp方法,可以在启动测试前进行一些初始化,比如测试类中的变量等初始化,这个方法需要添加@Before注解。

    说明:
    1. 上面的示例代码中可以直接使用assertEquals,是因为使用了静态import方法引入了相应的包(import static org.junit.Assert.*;
    2. 根据测试的功能合理使用androidTest和test,提高单元测试效率。

    2.2 自动生成测试类和测试方法

            上面介绍的是手动添加测试类和测试方法,以下介绍自动生成测试类和方法。在项目源码中选中需要添加单元测试的类并打开,在内容显示区域“右键”->“Go To”,在弹出窗口中选择“Test”,在弹出窗口中选择“Create New Test ......”

        在接下来弹出的对话框中,勾选需要添加单元测试的方法,在这里有个“Generate”通用方法生成,可以选择setUp/@Before(启动前调用,可用于初始化)和tearDown/@After(结束后调用)

    3. 运行单元测试

    3.1 运行单个测试方法

        在测试方法题内部,“右键”,在弹出菜单中选择“Run 方法名”即可(单元测试也可以使用断点调试和性能调试)。

    3.2 批量运行测试方法(有些情况下可能会无法实现)

        在终端使用gradle运行test任务,可以执行所有的单元测试方法(在AndroidStudio的Terminal运行gradlew test,在系统终端中运行gradle -p 项目路径 test,gradle没有配置环境变量,需要绝对路径),运行完成后,就会运行所有的单元测试方法,并且会显示结果,如下图:



    展开全文
  • 依稀记得还在学校学习JAVA的时候,那时候JUnit提供了很好用的单元测试体验。...Android单元测试Android单元测试有两种方式:本地单元测试和设备单元测试,本地单元测试可以直接运行在本地机器上面的

    依稀记得还在学校学习JAVA的时候,那时候JUnit提供了很好用的单元测试体验。然而在实际工作开发android快要两年了,还没有试过android是否也可以进行相似的单元测试从而避免每次一次写完功能之后都要花几分钟去RUN一遍。所以今天就来探究一下Android的单元测试。


    Android单元测试

    Android的单元测试有两种方式:本地单元测试设备单元测试,本地单元测试可以直接运行在本地机器上面的Java Virtual Machine(JVM)上面。它的特点是运行时间短,执行效率高,但是依赖Android framework,每个文件都可以进行单独的测试。
    运行在设备上的单元测试,运行的是一个单独的APK,直接运行到虚拟机或者设备上,这种单元测试拥有整个App的生命周期和运行环境。

    今天我们就来尝试一下进行这两种测试。

    这里写图片描述

    在android studio中新建项目的话,会自动为你创建测试目录(如上图)。

    本地单元测试

    创建一个普通的工具类来试一试吧。

    public class StringUtil {
    
        /**
         * @Date: 2016年7月10日14:48:34
         * @return : 判断两个String是否相同
         */
        public static boolean isSameString(String strSource, String strTarget) {
            // 都不为null
            if (null != strSource && null != strTarget) {
                return strSource.equals(strTarget);
            }
            // 两个都为null
            else if (null == strSource && null == strTarget) {
                return true;
            } else
            // 有一个为null
            {
                return false;
            }
        }
    }

    在test目录下创建一个Test类

    public class StringUtilTest {
        @Test
        public void testIsSameString(){
            Assert.assertFalse(StringUtil.isSameString(null,"123"));
            Assert.assertTrue(StringUtil.isSameString("123","123"));
        }
    }

    运行目录下所有测试

    运行目录下所有测试

    或者运行单个测试文件

    运行单个测试文件

    如果发现测试文件无法运行,需要将测试模式改为Unit Tests:

    需要将测试模式改为Unit Tests

    设备单元测试

    1.先将上面提到的测试模式改为 Android Instrumentation Tests。

    2.并在AndroidManifest.xml中application标签之前加入

        <instrumentation android:name="android.test.InstrumentationTestRunner"
            android:targetPackage="包名"
            android:label="test"/>

    为了使测试应用与原应用运行在同一进程,请填写原应用包名。

    3.在application标签中加入

    <uses-library android:name="android.test.runner"/>

    例子:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.ysdemo.empty">
    
        <instrumentation android:name="android.test.InstrumentationTestRunner"
            android:targetPackage="com.ysdemo.empty"
            android:label="test"/>
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <uses-library android:name="android.test.runner"/>
        </application>
    
    </manifest>

    4.依然测试刚才的StringUtil.java,在androidtest目录下创建StringUtilTest.java:

    public class StringUtilTest extends AndroidTestCase {
    
        public void testIsSameString(){
            Assert.assertFalse(StringUtil.isSameString(null,"123"));
            Assert.assertTrue(StringUtil.isSameString("123","123"));
            Log.i("YS!!","unit test!!");
        }
    }
    

    5.连接真机/虚拟机,进行设备单元测试

    这里写图片描述

    与本地单元测试基本相同,同时可以看到在Android Monitor里打出了log。

    总结

    android stduio自带的单元测试功能已经很强大,而且也简单易上手,可以考虑自己每每在写完一些重要功能之后先进行单元测试之后,再提交代码交付测试啦~
    下回预告:android单元测试第三方框架的使用

    展开全文
  • 为什么要做测试 撰写测试有以下好处: 确保开发出来的app功能是正确的 保证新增加的功能开发不会影响原来的功能,就是说新写的代码...本地单元测试:这种测试是运行在开发机器的JVM上的。存放在项目中app/src/test/j

    为什么要做测试

    撰写测试有以下好处:

    • 确保开发出来的app功能是正确的
    • 保证新增加的功能开发不会影响原来的功能,就是说新写的代码不会使原来正常工作的代码产生bug
    • 当采用测试驱动开发模式时,测试有助于模块化和迭代化。

    Android中的单元测试类型

    Android中的单元测试有两种类型

    1. 本地单元测试:这种测试是运行在开发机器的JVM上的。存放在项目中app/src/test/java目录下,这些测试不能引用Android Framwork 的API。例如你要测试一个纯逻辑的函数,就可以使用本地单元测试。
    2. 仪表单元测试:这种测试是运行在真机或者模拟器中的,可以引用Android Framwork中的API.存放在项目中app/src/androidTest/java目录下。

    为什么会出现这两种测试呢,因为Android编译后的字节码是针对移动设备优化的,它需要运行在特殊的JAVA虚拟机上Dalvik或者ART (Android Runtime),是不能直接运行在JVM上的。所以涉及到Android Framwork 依赖的函数如果不采用特殊的技术(稍后介绍),就需要使用 仪表单元测试,仪表单元测试需要安装两个完整的APKS到真机或者模拟器上,然后分别启动一个context,速度相比于本地单元测试那不是慢了一点两点。

    那么我们当然希望可以尽可能的使用本地单元测试,如果单元测试没有对Android的依赖,或者只是一些简单的引用使用第一种方法。这种场景下对Android的依赖可以使用Mockito来产生。还有我们可以使用开源库Robolectric来让Android代码可以运行在通用的JVM上。

    接下来将介绍如何完成上述的两种单元测
    假设我有一个算数计算类Calculator(google sample里面的例子),本类包括的加减乘除四个方法。

    package com.ss007.androidunittestsample;
    
    import static com.google.common.base.Preconditions.checkArgument;
    
    /**
     * A simple calculator with a basic set of operations.
     */
    public class Calculator {
    
        public enum Operator {ADD, SUB, DIV, MUL}
    
        /**
         * Addition operation
         */
        public double add(double firstOperand, double secondOperand) {
            return firstOperand + secondOperand;
        }
    
        /**
         * Substract operation
         */
        public double sub(double firstOperand, double secondOperand) {
            return firstOperand - secondOperand;
        }
    
        /**
         * Divide operation
         */
        public double div(double firstOperand, double secondOperand) {
            checkArgument(secondOperand != 0, "secondOperand must be != 0, you cannot divide by zero");
            return firstOperand / secondOperand;
        }
    
        /**
         * Multiply operation
         */
        public double mul(double firstOperand, double secondOperand) {
            return firstOperand * secondOperand;
        }
    }

    我们还有一个输入及结果展示界面

    输入界面

    本地单元测试

    由于Calculator类没有对Android的依赖,所以应当优先使用本地测试。

    不依赖Android的本地测试

    1. 在模块级别的build.gradle文件中添加相关库引用

      //本地单元测试依赖
      testImplementation 'junit:junit:4.12'
      //Mockito framework 用来模拟Android框架依赖
      testImplementation  'org.mockito:mockito-core:1.10.19'
    2. app/src/test/java目录下建立测试文件CalculatorTest,也可以选中要测试的函数,然后按Ctr+Shift+T建立测试文件。

      private Calculator mCalculator;
      
      @Before
      public void setUp() throws Exception{
          mCalculator = new Calculator();
      }
      
      @Test
      public void div() throws Exception    {
          double resultDiv = mCalculator.div(32d,2d);
          assertThat(resultDiv, is(equalTo(16d)));
      }
      
      @Test(expected = IllegalArgumentException.class)
       public void divDivideByZeroThrows() {
          mCalculator.div(32d,0d);
      }
      

      例如我们要测试Calculator中的除法这个函数,我们就定义一个或者几个测试函数,主要依赖你要测试的情况,使用@Test来标记,方法里面写断言即可。由于我们在测试函数中使用到了Calculator的实例,所以需要在测试函数执行前,构建出这个实例,这些初始化的工作在setUp函数中完成,这个函数使用@Before标记。
      就除法这个函数我们需要测试两种情况。第一正常情况下,除法计算是否正确。第二当除数为0的时候,我们是期望抛出合适的异常的,而不是崩溃。

    3. 运行单元测试
      运行测试用例可以分为多个维度
      单个测试函数,单个测试文件,单个目录下,测试Suite。
      最简单的运行方式就是直接Android Studio中选中相应的地方,右键然后选择run...即可,以Suite的方式运行的话首先需要自己将测试文件组织成不同的suite,然后依照自己的需求来运行不同的suite,这种方式更加灵活。

    4. 查看运行结果
      运行结果在AS的Run窗口,如下图所示

      Run窗口

    依赖Android的本地测试

    依赖Android的本地测试有两种处理方式

    • 针对于简单场景,可以使用Mockito来模拟Android的依赖,例如
    @RunWith(MockitoJUnitRunner.class)
    public class UnitTestSample {
    private static final String FAKE_STRING = "HELLO WORLD";
        @Mock
        Context mMockContext;
    
        @Test
        public void readStringFromContext_LocalizedString() {
            // 定义R.string.hello_word返回"HELLO WORLD"
            when(mMockContext.getString(R.string.hello_word))
                    .thenReturn(FAKE_STRING);
            //ClassUnderTest 我们要测试的类
            ClassUnderTest myObjectUnderTest = new ClassUnderTest(mMockContext);
    
            // ...when the string is returned from the object under test...
            String result = myObjectUnderTest.getHelloWorldString();
    
            // ...then the result should be the expected one.
            assertThat(result, is(FAKE_STRING));
        }
    }

    首先需要使用MockitoJUnitRunner这个类型的Runner,使用@RunWith(MockitoJUnitRunner.class)来标记测试类
    然后使用@Mock标记来模拟一个Android依赖。例如Context

    关于Mockito的详细使用可以参考Mockito API

    • 针对复杂场景,可以使用开源库Robolectric,通过该库单元测试可以直接运行在JVM上,Robolectric在Android SDK 的类加载过程中对其进行了重写,使其可以运行在JVM上。
    @RunWith(RobolectricTestRunner.class)
    public class MyActivityTest {
      @Test
      public void clickingButton_shouldChangeResultsViewText() throws Exception {
        MyActivity activity = Robolectric.setupActivity(MyActivity.class);
    
        Button button = (Button) activity.findViewById(R.id.button);
        TextView results = (TextView) activity.findViewById(R.id.results);
    
        button.performClick();
        assertThat(results.getText().toString()).isEqualTo("Robolectric Rocks!");
       }
    }

    需要使用RobolectricTestRunner这个类型的Runner

    关于更详细的使用请参考Robolectric

    仪表测试

    在进行仪表测试之前,先使用Android SDK 管理器下载Android Testing Support Library,Google 为测试优化了这个支持库,测试运行更加快速。这个库包含了用于JUnit4测试的AndroidJUnitRunner以及用于UI测试的API(EspressoUI Automator)。本文侧重使用Espresso

    使用Espresso进行Android仪表单元测试

    EspressoAndroid Testing Support Library中的一个测试框架,用来测试UI交互方面的功能。

    Espresso中主要由3个主要组件构成

    • ViewMatchers:从当前View 层级中获取目标View的一组对象集合。这些对象会作为参数传递到onView函数中来返回目标UI元素。
    • ViewActions:用来模拟用户操作,例如click等动作。这些对象会作为参数传入ViewInteraction.perform()中。
    • ViewAssertions:用来判断目标View的状态是否正确。这些对象会作为参数传入ViewInteraction.check()方法中。

      例如

        onView(withId(R.id.my_view))            // withId(R.id.my_view) - ViewMatcher
        .perform(click())                  // click() - ViewAction
        .check(matches(isDisplayed()));   //matches(isDisplayed()) - ViewAssertion
    配置Espresso
    1. 在模块级别的build.gradle中添加如下依赖
        // 仪表测试依赖    
        // Force usage of support annotations in the test app, since it is internally used by the runner            module.
        androidTestImplementation 'com.android.support:support-annotations:' + rootProject.supportLibVersion;
        // Android JUnit Runner
        androidTestImplementation 'com.android.support.test:runner:' + rootProject.runnerVersion;
        // JUnit4 Rules
        androidTestImplementation 'com.android.support.test:rules:' + rootProject.rulesVersion;
        // Espresso core
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:' + rootProject.espressoVersion;    

    android.defaultConfig里面添加
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    build.gradle 文件的配置完成后,大概像下面这样

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 26
        defaultConfig {
            applicationId "com.ss007.androidunittestsample"
            minSdkVersion 18
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        // 仪表测试依赖
        // Force usage of support annotations in the test app, since it is internally used by the runner module.
        androidTestImplementation 'com.android.support:support-annotations:' + rootProject.supportLibVersion;
        androidTestImplementation 'com.android.support.test:runner:' + rootProject.runnerVersion;
        androidTestImplementation 'com.android.support.test:rules:' + rootProject.rulesVersion;
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:' + rootProject.espressoVersion;
        //本地单元测试依赖
        testImplementation 'junit:junit:4.12'
    
        compile 'com.android.support:support-annotations:' + rootProject.supportLibVersion;
        compile 'com.google.guava:guava:18.0'
        implementation 'com.android.support:appcompat-v7:26.1.0'
        implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    }
    1. 配置测试机器
      关闭设备动画,到开发者模式->开发者选项->绘图下面 关闭三个缩放动画。

    2. 编写测试代码
      例如我们要测试我们的加法函数,输入两个数,然后点击相加按钮。

    
    @RunWith(AndroidJUnit4.class)//标记此类为Android JUnit4类
    @LargeTest//标记此类执行时间>1s,使用全平台资源
    public class CalculatorInstrumentationTest {
        @Rule//包括ActivityTestRule,里面提供了很多测试activity的函数,除此之外还有ServiceTestRule
        public ActivityTestRule<CalculatorActivity> mActivityRule = new ActivityTestRule<>(
                CalculatorActivity.class);
    
        @Test
        public void typeOperandsAndPerformAddOperation() {
            performOperation(R.id.operation_add_btn, "16.0", "16.0", "32.0");
        }   
    
        private void performOperation(int btnOperationResId, String operandOne,
                String operandTwo, String expectedResult) {
            //在两个 EditText 中输入操作数
            onView(withId(R.id.operand_one_edit_text)).perform(typeText(operandOne),
                    closeSoftKeyboard());
            onView(withId(R.id.operand_two_edit_text)).perform(typeText(operandTwo),
                    closeSoftKeyboard());
            //点击操作按钮,例如相加按钮
            onView(withId(btnOperationResId)).perform(click());
            //判断结果是否与我们期望的一致
            onView(withId(R.id.operation_result_text_view))
                  .check(matches(withText(expectedResult)));
        }
    }
    

    上面的代码完成了输入加数和被加数,然后点击求和按钮,检查结果是否正确的一套操作。

    本文源代码下载地址 AndroidUnitTestDemo

    展开全文
  • **我的目的,旨在介绍一个不一样的“单元测试” !** 其实对于单元测试这一块,我很早已经开始关注了,也搜罗了好多这方面技术的博客。要么只有文字性的,要么都是代码的逻辑类,笼统、没有什么脉络可循。之后依然半...

    这里写图片描述
    我的目的,旨在介绍一个不一样的“单元测试” !
    其实对于单元测试这一块,我很早已经开始关注了,也搜罗了好多这方面技术的博客。要么只有文字性的,要么都是代码的逻辑类,笼统、没有什么脉络可循。之后依然半解,放到项目中,用起来还是不方便,就是觉得这样比我直接运行在模拟器(真机)之后的过程打印、调试要慢好多!
    因此,就导致后来的放弃。以及今天的再次拾起,并做一个系统点的介绍,希望特别想要使用单元测试的朋友能够用得着。
    #不一样 、不一样的单元测试
    这里写图片描述
    上面,我截取了一个项目中module的目录结构图。看完之后,映入眼帘的是**红色框中那两个括弧**中的内容

    androidTest
    test

    她们俩是做什么的?我们就只从JUit出发,进行详细无死角的介绍


    ##JUnit 测试
    一般而言,使用Android Studio做安卓开发的我们对项目做测试,无论项目搭建的准备工作或是项目开发进行中的功能性测试。都无非用到两种环境下的测试:

    test androidTest
    Java环境下的测试 Android环境下的测试

    ###区别
    ####环境配置上的区别
    module下的build.gradle文件中那行行代码
    1,支持能够Java虚拟机设备环境下的默认环境配置

    /** build.gradle/dependencies{}中 **/
    testCompile 'junit:junit:4.12'
    

    2,支持能够Android设备环境下的默认环境配置

    /** build.gradle/dependencies{}中 **/
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
            exclude group: 'com.android.support', module: 'support-annotations'
        })
    /** 且android/defaultConfig{}节点要加上 **/
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    

    ####代码类配置的区别
    她们之间有明眼的区别,class注解上 的@RunWith(AndroidJUnit4.class)
    即可看到,IDE在两个包内也为我们生成的测试代码类
    在Android设备上执行的范例(androidTest)包下 && 在Java虚拟机设备上执行的范例(test)包

    好的,我们该如何使用呢?这是个关键问题!接下来看两种使用方式


    ###test包下的Java环境下的测试
    针对的是安卓项目。在基于MVP架构的基础上,使用OkHttp作网络数据请求,并对其做简单封装,以使用见最简单方式来实现与后台的数据交互。
    测试目的:测试get和post两种请求方式是否成功
    构建测试方式一 在要测试的类中 右击鼠标/Go To/Test/Create New Test..
    之后,你会发现新弹出的页面

    Testing library Class Superclass Destination Package Generate Generate test methods for member
    JUnit4 测试的类名 测试类的父类名 包名 勾选 不勾选 选择性勾选

    随便展示下图片效果,如图<图片很随便,内容真诚>
    这里写图片描述
    点击确定进入新的页面框,走入目录
    这里写图片描述
    当然是选择java虚拟机设备下的测试方式哦!
    然后测试类则生成,但是需要注意的是。你使用了这种方式并不会一定会生成你想要的效果。为什么?
    答案很简单,使用单元测试,测试的代码逻辑块必须是独立的。
    拿此例来说,使用okhttp的post方法做测试是否与后台能联通?那么,就必须让测试的代码逻辑块与无关的类解耦。比如在测试方法中以简洁的代码逻辑块 实现。或者,写一个管理类能直接管理post调用的操作。
    好,我上代码表示,以简洁的代码逻辑块 实现post请求

    	/**
         * 功能:使用post方式进行http请求的测试
         */
        @Test
        public void post() {
            MediaType JSON
                    = MediaType.parse("application/json; charset=utf-8");
    
            OkHttpClient client = new OkHttpClient();
            String url = "http://httpbin.org/post";
            RequestBody body = RequestBody.create(JSON, "{\"name\":\"xueshuyuan\"}");
            Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .build();
            Response response = null;
            try {
                response = client.newCall(request).execute();
                System.out.println("输出get方式请求的结果:==>>" + response.body().string());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    当然也能使用一个类先对上面的代码逻辑块 封装,然后在测试中一行代码逻辑搞定。

    一般的测试结构,就是生成了这样的效果。这种结构基本是固定的,所以自己完全可以在(test)包中手动创建。

    public class xxxTest {
    
        ...
    
        /**
         * 功能:在get()/post()方法执行之前优先执行
         * @throws Exception
         */
        @Before
        public void setUp() throws Exception {
            ..
        }
    
     
        @Test
        public void post() throws Exception {
    	    ..
        }
        @Test
        public void XXMethod() throws Exception {
    	    ..
        }
         /**
         * 功能:在加注解@Before的方法setUp()执行之后立即执行
         * @throws Exception
         */
    	@after
    	public void TearDown() throws Exception {
    		..
    	}
    
    }
    

    其中,上标注了@Before @after 方法名是固定的,并且执行顺序也是固定的。

    比如对方法post进行测试,右击鼠标,选中执行Run 'post()'
    这里写图片描述
    打印结果:
    这里写图片描述

    如果我换一个单元测试类,这时用到了Rxjava进行了线程的调度,但依然是基于Java环境的单元测试

    /**
     * @Title:RxjavaTestInJava 
     * @Auther:YJH
     * @Email:yuannunhua@gmail.com
     * @Date:2018/6/23 20:13
     */
    public class RxjavaTestInJava {
    
        @Before
        public void setUp() throws Exception {
            Thread.currentThread().setName("currentThread");
        }
    
        @Test
        public void schedulerTest() {
            //观察者(订阅者)
            final Subscriber<String> subscriber = new Subscriber<String>() {
                @Override
                public void onCompleted() {
    
                    System.out.println("onCompleted=" + Thread.currentThread().getName());
                }
    
                @Override
                public void onError(Throwable e) {
                    System.out.println("onError=" + Thread.currentThread().getName());
                    e.printStackTrace();
                }
    
                @Override
                public void onNext(String result) {
                    System.out.println("onNext=" + Thread.currentThread().getName());
                    System.out.println("onNext=" + result);
    
                }
            };
    
            //被观察者
            final Observable observable = Observable.create(new Observable.OnSubscribe<Subscriber>() {
    
                @Override
                public void call(Subscriber subscriber1) {
    
                    System.out.println("Observable-call=" + Thread.currentThread().getName());
                    subscriber1.onStart();
                    subscriber1.onNext("hello world");
                    subscriber1.onCompleted();
                }
            });
    
    
            observable.subscribeOn(Schedulers.io()) //指生产事件在当前的线程中进行
                    .observeOn(AndroidSchedulers.mainThread()) //指消费事件在主线程中进行
                    .subscribe(subscriber);
    
        }
    
        public class User {
            private String name;
    
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    
    }
    

    接下来你会看到报错、报错
    这里写图片描述

    但如果,我把第56行代码换掉,换作.observeOn(Schedulers.newThread())结果又会不同且正常执行。那是为什么呢?


    ###androidTest 包下的Android环境下的测试
    原因是,在第56行代码使用了Android的API,已经不是能在Java环境下正常执行的了。所以为了执行该代码逻辑块,看看是否是我们想要的逻辑代码。这时就需要执行在Android环境下。即在(androidTest)包下新建一个同样的类逻辑,只做些许的必要修改 (改变参照两种测试环境的不同而做改变)
    1,类名上添加注解 @RunWith(AndroidJUnit4.class)
    2,增加一些Android平台的注释 Log.e 以做日志打印

    /**
     * @Title:RxjavaTestInJava 
     * @Auther:YJH
     * @Email:yuannunhua@gmail.com
     * @Date:2018/6/23 20:13
     */
     
    @RunWith(AndroidJUnit4.class)
    public class RxjavaTestInJava {
     @Before
        public void setUp() throws Exception {
            Thread.currentThread().setName("currentThread");
        }
    
    
        @Test
        public void schedulerTest() {
            final String tag = "test";
            //观察者(订阅者)
            final Subscriber<String> subscriber = new Subscriber<String>() {
                @Override
                public void onCompleted() {
    
                    System.out.println("onCompleted=" + Thread.currentThread().getName());
                    Log.e(tag, "onCompleted=" + Thread.currentThread().getName());
                }
    
                @Override
                public void onError(Throwable e) {
                    System.out.println("onError=" + Thread.currentThread().getName());
                    e.printStackTrace();
                }
    
                @Override
                public void onNext(String result) {
                    System.out.println("onNext=" + Thread.currentThread().getName());
                    System.out.println("onNext=" + result);
                    Log.e(tag, "onNext=" + result);
    
                }
            };
    
            //被观察者
            final Observable observable = Observable.create(new Observable.OnSubscribe<Subscriber>() {
    
                @Override
                public void call(Subscriber subscriber1) {
    
                    System.out.println("Observable-call=" + Thread.currentThread().getName());
                    Log.e(tag, "Observable-call=" + Thread.currentThread().getName());
                    subscriber1.onStart();
                    subscriber1.onNext("hello world");
                    Log.e(tag, "hello world");
                    subscriber1.onCompleted();
                }
            });
    
    
            observable.subscribeOn(Schedulers.io()) //指生产事件在当前的线程中进行
                    .observeOn(AndroidSchedulers.mainThread()) //指消费事件在主UI线程中进行
                    .subscribe(subscriber);
    
    
        }
    
    
        public class User {
            private String name;
    
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    }
    

    然后同样的执行方式,在方法schedulerTest右击鼠标并**run ‘schedulerTest()’**执行测试!
    这里写图片描述
    然后你会看到弹窗
    这里写图片描述
    然后你会发现该指示是让你启动一个Android模拟器设备,显然是要运行到上面了。然而结果却是app并不会到模拟器上启动,而是"后台运行"。以这种方式执行了我们的单元测试。
    欣赏下Run下的执行结果
    这里写图片描述
    然后欣赏下Android Monitor下的执行结果
    这里写图片描述
    说明一切都在我们的掌握之中,能够让我看到该单元测试结果,并能够确认该逻辑是否是我们想要的正确逻辑,从而起到单元测试的作用!

    展开全文
  • Android单元测试

    2015-12-25 09:08:35
    虽然要进行单元测试并不复杂,但是其中的关系好像有点复杂,包括怎样在Eclipse进行单元测试,又怎样在Android Studio进行单元测试,怎样进行Local的测试而不需要运行真机或虚拟机,各种TestCase有什么不同,为什么...

    前言

    对于Android的单元测试一直有些弄不明白,虽然要进行单元测试并不复杂,但是其中的关系好像有点复杂,包括怎样在Eclipse进行单元测试,又怎样在Android Studio进行单元测试,怎样进行Local的测试而不需要运行真机或虚拟机,各种TestCase有什么不同,为什么Junit4好像很难work的样子…等等问题,我试着一一弄明白这些问题。这篇文章不涉及UI测试。


    简介

    单元测试是app的基础测试,为你的代码编写单元测试,可以很容易地验证程序的某个单元是否正确。当你改动代码之后,如果程序发生了错误,单元测试则可以帮助你快速发现这些错误。
    单元测试以一种可重复的方式测试程序的最小单元,比如方法、类或者组件。为了验证特定代码单元的逻辑是否正确,你应该编写单元测试。通常情况下,单元测试与工程代码分离,测试只会影响到测试单元本身。而mocking框架可以将你的测试单元与其依赖分离。


    ADT Eclipse进行单元测试

    我们首先来看一下Eclipse怎样进行Android单元测试。

    1、建立一个UnitTestDemo工程
    2、为工程配置测试环境
    这里写图片描述
    然后在AndroidManifest文件Application节点下添加一条语句:

    <uses-library android:name="android.test.runner" />

    这样配置完成了
    这里写图片描述
    3、编写一个待测试的类,这个类我们会在后面多次用到。

    public class Calculator {
    
        public int add(int a, int b) {
            return a + b;
        }
    
        public int dec(int a, int b) {
            return a - b;
        }
    
    }

    4、为待测试类编写单元测试类,文件放在哪随意,最好把所有测试都放在新建的一个test包啦。

    import junit.framework.TestCase;
    
    public class CalculatorTest extends TestCase {
    
        public void testAdd() {
            Calculator calculator = new Calculator();
            assertEquals(2, calculator.add(1, 1));
        }
    
        public void testDec() {
            fail("Not yet implemented");
        }
    
    }

    5、右击CalculatorTest类,Run As -> Android Junit Test,启动真机或模拟器后即可看到测试结果了。
    这里写图片描述

    这样我们就完成了最简单的但也很实用的单元测试了。

    如果在Eclipse环境下使用过Junit的同学一定会感到奇怪,IDE没有像编写Java程序那样提示我们:
    这里写图片描述

    下一节来说明


    认识

    为什么我们Android工程只需要写了配置就可以进行单元测试,好像我们都没有导入Junit框架。原因是,Android SDK本身就内置了基于Junit3的测试框架。我们查下API历史,发现从API 1就已经内置了测试框架了。
    这里写图片描述

    基于Junit3,整个Android内置的测试框架如下图。
    这里写图片描述

    关于各种测试有何不同可以参考:

    http://developer.android.com/reference/android/test/package-summary.html
    http://stackoverflow.com/questions/2047261/using-android-test-framework/2055455#2055455

    因为不涉及UI测试,需要用到Context就继承AndroidTestCase,有个getContext方法;不需要直接就继承TestCase和Junit3一样使用。


    Android Studio进行单元测试

    有了上面的认识,我们知道了Android SDK本身就内置了以Junit3为基础的Android测试框架,而Android Studio本身就默认帮我们配置好了测试环境,所以直接就可以上测试了。

    1、建立一个UnitTestDemo Module
    2、编写一个待测试的类,直接拷贝上面的。
    3、自动生成测试类,生成的代码位置androidTest目录下,编辑测试代码。
    这里写图片描述
    这里写图片描述

    4、右击CalculatorTest类,Run,启动真机或模拟器后即可看到测试结果了。
    这里写图片描述

    解决了Eclipse和AS进行基本单元测试的问题,还有两个问题值得探讨:
    1、每次测试都要启动真机或者模拟器,有没办法进行本地测试;
    2、难道就不能用Junit4吗?


    本地测试与Junit4

    首先来了解一下两个概念:

    Local tests:代码被编译成运行在本地JVM的单元测试,使用Local tests无需依赖Android框架,但可以通过mock注入依赖。
    Instrumented(Instrumentation) tests:运行在真机或者模拟器的单元测试,这些测试可以获得真机环境,比如context。当难以通过mock注入Android框架的依赖时,就可以使用这种测试。

    现在我们知道上面提到的两个例子都是Instrumentation tests。通过继承AndroidTestCase,我们就能分分钟得到context对象啦。不过使用Instrumentation Test每次都要启动一下真机或者模拟器,消耗较多资源,理论上来讲Local Test可以大幅减少测试时间。

    1、配置Local Test环境,选择Unit Tests
    这里写图片描述

    2、导入依赖

    testCompile 'junit:junit:4.12'

    3、新建一个test/java包,必须。
    这里写图片描述

    4、和上面一样,自动生成测试类,生成的代码位置test目录下,编辑测试代码。
    这里写图片描述

    5、右击CalculatorTest类,Run。这一次无需启动真机或模拟器就可以运行了。
    这里写图片描述

    刚才提到本地测试很大原因是为了一个字快,理论上确实应该更快,然而在我的渣机器上还不如Instrumentation Test快…

    我们一下子就实现了本地测试并且使用的是Junit4,Junit4是使用注解的测试框架,无需像Junit3一样测试方法必须使用test开头。上面这个例子我们自动生成的测试类同样可以使用Junit3。
    如果我们把步骤2中的Junit4依赖去掉,Junit4不能使用这是不言而喻的,原本在Instrumentation Test可以使用的Junit3呢?答案是不能的,因为单元测试需要Runner,翻到最上面Eclipse那个工程可以看到Android默认的Runner是InstrumentationTestRunner,当我们使用Local Test时因为导入了Junit4依赖,AS能找到Junit4的Runner,怎么着也应该能兼容Junit3吧;而如果把Junit4依赖去掉,AS就找不到合适的Runner来Run这个Junit3的Local Test了。
    最后Instumentation Test能使用Junit4吗,答案是可以的,但是配置起来比较麻烦,这里就不多纠结了,有爱可以参考。
    https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html#build


    小结

    1、Android内置基于Junit3的测试框架,默认Runner是InsrtumentationTestRunner。
    2、Instrumentation Test需要启动真机或模拟器,默认可以使用Junit3,可以通过配置使用Junit4。
    3、Local Test无需启动真机或模拟器,导入Junit4依赖后,支持Junit4兼容Junit3。Local Test不能依赖于Android框架,如果需要注入Android依赖,可以通过mock技术。

    这篇文章未涉及的主题包括:
    mock和UI测试。

    讲了这么一大堆怎样实现单元测试,那究竟测试代码应该怎样写呢。可以参考一些牛库的测试,比如OkHttp:
    https://github.com/square/okhttp/tree/master/okhttp-tests/src/test/java/okhttp3

    参考:

    展开全文
  • Android单元测试

    2018-11-20 11:42:04
    单元测试 关于单元测试,在维基百科中,给出了如下定义: 在计算机编程中,单元测试(英语:Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试...android中的单元测试...
  • 前言 为了这个AndroidStudio的...我的AndroidStudio我的AndroidStudio是1.5.1版本,但是进行单元测试应该很早的版本就可以了,至少可以追溯到1.0注意事项当你google查找AndroidStudio单元测试时,有大量的资料教程,
  • 本文我们将讲解如何在Android studio中进行单元测试。在Android开发项目中,经常会进行测试操作,而一次又一次的运行模拟器,浪费了大量时间,降低了工作效率降低,虽然最新的Android studio中提供了instance run...
  • Android单元测试全解

    2020-01-08 13:35:33
    单元测试:既然Java可以进行单元测试Android为什么就不可以呢? 一键适配:不解释 正式开车! 1、Java单元测试 Android studio(以下简称as)可以跑纯Java代码,这个想必大家都知道。这里就简单介绍一下as.....
  • 本地单元测试(Junit Test), 本地单元测试是纯java代码的测试,只运行在本地电脑的JVM环境上,不依赖于Android框架的任何api, 因此执行速度快,效率较高,但是无法测试Android相关的代码。 Android单元测试(Android...
  • 单元测试 在软件开发中一直在推崇TDD(测试驱动开发),但是一直不能被有效的执行或者并不是真正的测试驱动开发(先开发后写单元测试),因为我们懒!...关于Android Studio如何编写单元测试运行,可以看之前
  • 单元测试的作用 在Android开发中,如果对一个简单的功能,每次修改代码都重新运行到设备中进行测试,会浪费大量时间,降低开发工作效率。如果使用单元测试,编写单元测试类,执行测试单元测试类就可以对某些功能进行...
  • 如果你的单元测试没有依赖项或者仅仅有一些简单的Android依赖项,那么你应该在本地开发机上去运行你的测试。 这种测试的方式是非常高效的,因为它避免了去加载你的app和测试代码到真机或者模拟器上的开销。相应地,...
  • 可能有很多人经常会听到这个词并不感到陌生,那什么是单元测试呢,在Android中又是如何实践的呢,这个时候可能会感到困惑。从名字上看,单元测试就是参与项目开发的工程师在项目中为了测试某一个代码单元而写的测试...
  • 1.前言网上有许多关于单元测试的好处,这里我就不去说了。我写单元测试的理由很简单粗暴,就是图一个方便。如果你想早点写完下班,那么你就需要掌握单元测试
  • Android自带单元测试运行方法,有兴趣的可以尝试下: 1.下载Android源码,并执行一次编译 2.使用模拟器加载编译完成的三个镜像 内核可以使用/prebuilt/android-arm/kernel/kernel-qeum-armv7 注意使用-...
  • 本文假设你已经知道如何adb连接设备,知道如何在eclipse里运行android单元测试。 关键命令: [code="shell"] 直接运行所有有case adb shell am instrument -w ...
  • 目录在Android Studio中进行单元测试和UI测试 - 1.概述在Android Studio中进行单元测试和UI测试 - 2.创建新的Android Studio工程在Android Studio中进行单元测试和UI测试 - 3.配置支持单元测试的工程在Android ...
  • 关于Android单元测试

    2017-04-16 19:09:40
    【转载自美团点评技术团队的一篇文章,原文在这里:...】Android单元测试介绍处于高速迭代开发中的Android项目往往需要除黑盒测试外更加可靠的质量保障,这正是单元测试的用武之地。单元测
1 2 3 4 5 ... 20
收藏数 24,571
精华内容 9,828
关键字:

单元测试 运行android