• Android 单元测试(junit、mockito、robolectric)


    1、运用JUnit4 进行单元测试

    首先在工程的 src 文件夹内创建 test 和 test/java 文件夹。 

    打开工程的 build.gradle(Module:app)文件,添加JUnit4依赖,点击Gradle sync按钮。

    build.gradle

    1 dependencies {
    2     testCompile 'junit:junit:4.12'
    3 }

    (1)新建被测类:

    1 public class Calculator {
    2 
    3     public double sum(double a, double b){
    4         // 假设先返回结果0  
    5         return 0;
    6     }
    7 }

    (2)新建测试类:

    
    
    import org.junit.Before;
    import org.junit.Test;
    import static org.junit.Assert.*;
    public class CalculatorTest {
    
        private Calculator mCalculator;
    
        @Before
        public void setUp() throws Exception {
            mCalculator = new Calculator();
        }
    
        @Test
        public void testSum() throws Exception {
            //断言:1+1 = 2
            assertEquals(mCalculator.sum(1d, 1d),  2d);
        }
    }

    这时候 右键 - testSum()方法,选择选择Run > testRun , 也可以通过命令行运行测试,在工程目录内输入:

    1 ./gradlew test

    这时测试因为我写被测类的时候,返回的是0,所以跟期望的值不一样,就会失败。

    这时,我们修改下Calculator.java的函数:

    1 public double sum(double a, double b){
    2     return a + b;
    3 }

    保存,这时候再运行测试,成功,跟期望值一样。

    总结:位于src/tests目录下的测试是运行在本地电脑Java虚拟机上的单元测试。

    编写测试,实现功能使测试通过,然后再添加更多的测试,这种工作方式使快速迭代成为可能,我们称之为测试驱动开发

    2、使用Mockito等mocking框架来mock测试。

    Mock:

    mock对象就是在调试期间用来作为真实对象的替代品。

    mock测试就是在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试。

    打开工程的 build.gradle(Module:app)文件,添加Mockito依赖,点击Gradle sync按钮。

    build.gradle

    1 dependencies {
    2     // 单元测试
    3     testCompile 'org.mockito:mockito-all:2.0.2-beta'
    4     testCompile 'junit:junit:4.12'
    5 }

    关于mokito的使用,官网已经给出很详细了。我这里主要想记录下主要用到的。对于mvp架构下,测试presenter返回到view的数据,是否正确。

    配合mvp模式下,利用本地json,模仿网络请求,进行模拟数据,查看presenter 处理逻辑是否正确。

    public class PresenterTest {
    
        @Mock
        Repository repository; // 网络请求
        @Mock
        View view; // view
    
        PresenterImpl presenter;
    
        @Before
        public void setUp() throws Exception {
            // 如果有使用到rxjava,可以在这里处理rxjava变成同步执行
            MockitoAnnotations.initMocks(this);
    
            presenter = new PresenterImpl(view, repository);
        }
    
        @Test
        public void getOrderList() throws Exception{
            String json = readAssetsJSON("get_list.json").optString("data");
            List<ViewModel> list = JSON.parseArray(json, ViewModel.class);
    
            when(repository.getList(1)).thenReturn(Observable.just(list));
            presenter.getList(1);
    
            ArgumentCaptor<ArrayList> captor = ArgumentCaptor.forClass(ArrayList.class);
            verify(presenter.getView()).onGetDataByFinish(captor.capture());
    
            List<ViewModel> viewModels = captor.getValue();
    
            assertEquals(list.size(), viewModels.size());
        }
    }

     get_list.json 是放到 src/test下的assets 目录下,这个目录在:打开工程的 build.gradle(Module:app)文件,android节点下的sourceSets节点下,配置下:

    1 sourceSets {
    2         main {
    3             .....
    4         }
    5 
    6         test {
    7             java.srcDirs = [ 'src/test/java']
    8         }
    9     }

    其他的用法:参考下官方就行,因为官网是英文的,看不懂的,还可以前往:Mockito 中文文档

    3、使用Robolectric 

    Robolectric 是一个针对于Android SDK 的单元测试框架,使用它可以测试驱动你的Android应用程序的开发。测试用例只需要在JVM基础上就能运行起来。

    打开工程的 build.gradle(Module:app)文件,添加Robolectric依赖,点击Gradle sync按钮。

    build.gradle

    1 dependencies {
    2     // 单元测试
    3     testCompile 'org.robolectric:robolectric:3.1-rc1'
    4     testCompile 'org.mockito:mockito-all:2.0.2-beta'
    5     testCompile 'junit:junit:4.12'
    6 }

    1、创建一个WelcomeActivity, 点击登录,跳转到登录页面。

    布局文件:

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
        android:layout_height="match_parent">  
        
    <Button          android:id="@+id/btn_login"
    android:text="click the btn"          android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>   </LinearLayout> 

    Activity:

    public class WelcomeActivity extends Activity {  
        @Override 
        protected void onCreate(Bundle savedInstanceState) {       
            super.onCreate(savedInstanceState); 
            setContentView(R.layout.welcome_activity);  
            final View button = findViewById(R.id.btn_login); 
            button.setOnClickListener(new View.OnClickListener() {  
                @Override 
                public void onClick(View view) { 
                    startActivity(new Intent(getContext(), LoginActivity.class));     
               }      
            });
         }
     }

    测试的是:当用户点击登陆按钮后,我们启动了正常的intent。

    由于Robolectric只是一个模拟的单元测试框架,LoginActivity并不会真正的启动,但是我们可以检查是否准确的发出了WelcomActivity的intent。 

     1 @RunWith(RobolectricTestRunner.class 2 public class WelcomeActivityTest {  
     3     @Test 
     4     public void clickingLogin_shouldStartLoginActivity() { 
     5         WelcomeActivity activity = Robolectric.setupActivity(WelcomeActivity.class);       
     6       activity.findViewById(R.id.btn_login).performClick();  
     7         Intent expectedIntent = new Intent(activity, WelcomeActivity.class);         
     8      assertThat(shadowOf(activity).getNextStartedActivity()).isEqualTo(expectedIntent);  
     9    } 
    10

    判断点击后textview 文本变化是否正常等:

     1 @RunWith(RobolectricTestRunner.class)
     2 public class WelcomeActivityTest {
     3  
     4   @Test
     5   public void clickLoginButton() throws Exception {
     6     Activity activity = Robolectric.buildActivity(WelcomeActivity.class).create().get();
     7  
     8     Button btn_login = (Button) activity.findViewById(R.id.btn_login);
     9     TextView tv_result = (TextView) activity.findViewById(R.id.tv_result);
    10  
    11     btn_login.performClick();
    12     String resultsText = tv_result.getText().toString();
    13     assertThat(resultsText, equalTo("Click the login button"));
    14   }
    15 }

    对于控制activity的生命周期,Robolectric 2.2版本以后增加了控制activity方法:

    1 Activity activity = Robolectric.buildActivity(WelcomeActivity.class).create().get();

    这会创建一个WelcomeActivity,并且已经调用了onCreate()。

    (1)检查一些在onCreate()和onResume()之间发生的事件:

    1 ActivityController controller = 
    2           Robolectric.buildActivity(WelcomeActivity.class).create().start(); 
    3 Activity activity = controller.get(); 
    4 // assert that something hasn't happened 
    5 activityController.resume(); 

    (2)完整的生命周期:

    1 Activity activity = 
    2       Robolectric.buildActivity(WelcomeActivity.class).create().start().resume().visible().get(); 

    (3)使用intent 来启动activity:

    1 Intent intent = new Intent(Intent.ACTION_VIEW); 
    2 Activity activity = 
    3     Robolectric.buildActivity(WelcomeActivity.class).withIntent(intent).create().get();

    (4)保存状态:

    1 Bundle savedInstanceState = new Bundle(); 
    2 savedInstanceState.putExtra("user_age", "18");
    3 savedInstanceState.putExtra("user_name", "jay");
    4 Activity activity = Robolectric.buildActivity(WelcomeActivity.class).create() 
    5        .restoreInstanceState(savedInstanceState).get(); 
  • 相关阅读:
    vpp编写plugin
    vrf 命令
    vxlan + 多个vrf
    dpdk helloworld
    Go函数高级
    Go_defer
    Go递归函数
    Go作用域
    Go函数
    Go字符串
  • 原文地址:https://www.cnblogs.com/CharlesGrant/p/5765843.html
Copyright © 2020-2023  润新知