使用Junit對Android應用進行單元測試

2021-01-08 IT168

  【IT168技術】在本文中,你將會學習到如何在Eclipse中創建Android JUnit的單元測試工程以及在不同的條件下創建及運行自動測試用例。

  準備工作

  本文假設讀者已經有一定的Android基礎知識,並且已經安裝了Eclipse和Android SDK等開發工具。本文將指導讀者如何將Android Junit框架應用到Android應用中去。本文還特別重點展示了如何測試Android中的Activity和如何識別程序中的錯誤。

  本文的示例代碼可以在http://code.google.com/p/simple-calc-unit-testing/中下載

  步驟1 被測試的應用SimpleCalc概況

  在本文中,將以一個寫好了的應用SimpleCalc簡單計算器為例子進行講解。這個簡單計算器有兩個功能,允許用戶輸入兩個數並將它們相加或相乘,最後顯示結果,如下圖所示:


                           

        步驟2 SimpleCalc的的界面設計

  由於應用比較簡單,只佔一屏,所以我們在/res/layout/main.xml中設計如下代碼所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:text="@string/hello"
        android:gravity="center_horizontal" android:textSize="48px"
        android:padding="12px" />
    <EditText android:layout_height="wrap_content" android:id="@+id/value1"
        android:hint="@string/hint1" android:inputType="numberDecimal"
        android:layout_width="fill_parent" android:textSize="48px"></EditText>
    <EditText android:layout_height="wrap_content" android:id="@+id/value2"
        android:hint="@string/hint2" android:inputType="numberDecimal"
        android:layout_width="fill_parent" android:textSize="48px"></EditText>
    <FrameLayout android:id="@+id/FrameLayout01"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:padding="12px" android:background="#ff0000">
        <LinearLayout android:id="@+id/LinearLayout02"
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:orientation="horizontal" android:background="#000000"
            android:padding="4px">
            <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content" android:text="@string/resultLabel"
                android:textSize="48px" android:id="@+id/resultLabel"></TextView>
            <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content" android:id="@+id/result"
                android:textSize="48px" android:textStyle="bold"
                android:layout_marginLeft="16px"></TextView>
        </LinearLayout>
    </FrameLayout>
    <LinearLayout android:id="@+id/LinearLayout03"
        android:layout_height="wrap_content" android:layout_width="fill_parent">
        <Button android:layout_height="wrap_content" android:id="@+id/addValues"
            android:text="@string/add" android:textSize="32px"
            android:layout_width="wrap_content"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/multiplyValues"
            android:text="@string/multiply" android:textSize="32px"
            android:layout_width="wrap_content"></Button>
    </LinearLayout>
</LinearLayout>

        簡單解析一下這個界面設計,我們使用了LinearLayout,以使得控制項能在垂直方向豎向排列。界面中包括了顯示標題「Unit Testing Sample」的textview,兩個輸入數字的edittext控制項,一個FrameLayout控制項中包含了一個水平的LinearLayout,在這個LinearLayout包含了一個顯示結果的textview以及其提示文字「Result」,注意的是FrameLayout的背景顏色設置為紅色,而LinearLayou設置成了黑色背景。

        步驟3 SimpleCale Activity

  本程序中只有一個Actity:MainActity.java,代碼如下:

package com.mamlambo.article.simplecalc;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       final String LOG_TAG = "MainScreen";
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

       final EditText value1 = (EditText) findViewById(R.id.value1);
       final EditText value2 = (EditText) findViewById(R.id.value2);

       final TextView result = (TextView) findViewById(R.id.result);

       Button addButton = (Button) findViewById(R.id.addValues);
       addButton.setOnClickListener(new OnClickListener() {

           public void onClick(View v) {
               try {
                   int val1 = Integer.parseInt(value1.getText().toString());
                   int val2 = Integer.parseInt(value2.getText().toString());

                   Integer answer = val1 + val2;
                   result.setText(answer.toString());
               } catch (Exception e) {
                   Log.e(LOG_TAG, "Failed to add numbers", e);
               }
           }
       });

       Button multiplyButton = (Button) findViewById(R.id.multiplyValues);
       multiplyButton.setOnClickListener(new OnClickListener() {

           public void onClick(View v) {
               try {
                   int val1 = Integer.parseInt(value1.getText().toString());
                   int val2 = Integer.parseInt(value2.getText().toString());

                   Integer answer = val1 * val2;
                   result.setText(answer.toString());
               } catch (Exception e) {
                   Log.e(LOG_TAG, "Failed to multiply numbers", e);
               }
           }
       });
   }
}

 

  上面的代碼十分簡單,分別在兩個按鈕的onclick事件中,對用戶輸入的數進行了相加和相乘,看上去代碼似乎沒問題,但接下來,我們將通過Junit去發現其中的bug。

  步驟4 創建Android 單元測試工程

  可以有兩種方法去增加單元測試工程:一種是在創建新的Android工程時,在創建嚮導時同時創建單元測試工程,另外是針對已有的項目工程添加一個單元測試工程。本文由於已經有了一個項目工程,所以用如下步驟增加單元測試工程:


  在Eclipse中,選擇存在的工程SimpleCalc,滑鼠右鍵後在彈出的菜單中選擇Android Tools-àNew Test Project,如下圖所示:

  步驟5 設置測試工程

  接下來需要對單元測試的工程進行設置,我們採用如下的設置方法:

  l 測試工程名稱:我們採用SimpleCalcTest

  l 工程的位置:這個可以隨便設置

  l 選擇被測試的工程:這裡我們選擇已經存在的SimpleCalc

  l 構建的目標版本:這裡我們選擇Android 2.1

  l 測試用例的包名:設置為com.mamlambo.article.simplecalc.test,

  l 設置界面如下圖所示。


  步驟6 SimpleCalcTest單元測試項目的結構

  我們審視下SimpleCalcTest的項目結構如下圖所示,可以看到這跟普通的Android工程沒什麼兩樣:


  步驟7 創建單元測試用例

  下面創建第一個單元測試用例,滑鼠右鍵點擊simplecalc.test的包,在彈出的菜單中選擇NewàJUnit Test Case,如下圖所示:


  步驟8 設置單元測試用例

  接下來對單元測試進行如下設置

  l 設置選擇使用Junit 3

  l 原始碼目錄:這裡要設置為SimpleCalcTest工程的代碼目錄

  l Package:這裡設置為com.mamlambo.article.simplecalc.test,

  l 測試用例名稱:設置為MathValidation

  l 測試的父類:這裡選擇「android.test.ActivityInstrumentationTestCase2.",這個是用來測試activity的Android的測試用例

  l 將多選框中的setup,constructor兩個都勾選上

  如下圖所示


  步驟9 查看MatthValidation測試用例

  在上圖中,點」Finish」按鈕後,MathVlidatiton.java測試用例就創建了。在單元測試中包括如下幾個部分:construction, setUp(), 針對方法的測試用例, tearDown(), 和destruction。在setup()方法中,主要是實現一些在測試工作前的資源及環境設置等的初始化設置;而針對方法的測試用例中,需要用戶自己編寫,一般是以「test+方法名」;而tearDown()在每個測試方法之後運行,用來撤消其初始化的測試環境。

  代碼如下:

package com.mamlambo.article.simplecalc.test;

import android.test.ActivityInstrumentationTestCase2;

public class MathValidation extends
       ActivityInstrumentationTestCase2<MainActivity> {  

   public MathValidation(String name) {
       super(name);
   }

   protected void setUp() throws Exception {
       super.setUp();
   }
}

  步驟10 修改MathValidation的構造函數

  在測試用例的構造函數中,寫入如下代碼,以將我們正在使用的測試父類與測試環境設置進行綁定。

  public MathValidation() {

  super("com.mamlambo.article.simplecalc", MainActivity.class);

  }

  步驟11 編寫setUp方法

  現在可以收集數據去驗證SimpleCalc的計算方法了。在setUp方法中,首先應該通過getActivity()方法獲得當前的Activity,如下所示:

  MainActivity mainActivity = getActivity();

  接著,需要獲得名為R.id.result的textview控制項的實例,這個控制項實際上保存計算器應用的運算結果的,代碼如下所示:

package com.mamlambo.article.simplecalc.test;

import android.test.ActivityInstrumentationTestCase2;
import android.widget.TextView;
import com.mamlambo.article.simplecalc.MainActivity;
import com.mamlambo.article.simplecalc.R;

public class MathValidation extends ActivityInstrumentationTestCase2<MainActivity> {

   private TextView result;

   public MathValidation() {
       super ("com.mamlambo.article.simplecalc", MainActivity.class);
   }

   @Override
   protected void setUp() throws Exception {
       super.setUp();

       MainActivity mainActivity = getActivity();

       result = (TextView) mainActivity.findViewById(R.id.result);
   }
}

  步驟12 SimpleCalc計算器中的加法測試用例

  我們首先針對SimpleCalc中的加法進行測試用例的編寫。這個測試用例中,會輸入兩個數(24和74),並測試是否其結果等於98。為了模擬在輸入數字後點按鈕的效果,我們使用了sendkeys方法,這個方法的優點在於可以在輸入後自動將焦點切換到下一個控制項上。最後,我們使用assertTrue的斷言去判斷實際結果是否就是等於98,代碼如下:

  private static final String NUMBER_24 = "2 4 ENTER ";

  private static final String NUMBER_74 = "7 4 ENTER ";

  private static final String ADD_RESULT = "98";

  public void testAddValues() {

  sendKeys(NUMBER_24);

  // now on value2 entry

  sendKeys(NUMBER_74);

  // now on Add button

  sendKeys("ENTER");

  // get result

  String mathResult = result.getText().toString();

  assertTrue("Add result should be 98", mathResult.equals(ADD_RESULT));

  }

  步驟13 改進測試用例

  由於每次測試時,其實都是使用同一個activity的,因此在每次測試時不需要清除舊的值,我們可以在一個sendKeys()方法中,發送一系列的輸入命令,如下所示:

  sendKeys(NUMBER_24 + NUMBER_74 + "ENTER");

  我們測試一個小數的情況如下,看結果是否等於79.5

  public void testAddDecimalValues() {

  sendKeys(NUMBER_5_DOT_5 + NUMBER_74 + "ENTER");

  String mathResult = result.getText().toString();

  assertTrue("Add result should be " + ADD_DECIMAL_RESULT + " but was "

  + mathResult, mathResult.equals(ADD_DECIMAL_RESULT));

  }

  同樣,我們去編寫乘法的單元測試用例,這裡我們繼續使用sendKeys()方法,由於乘法的按鈕就在加法的按鈕右邊,所以我們在用sendkey模擬輸入了兩個數後,發送「DRAD_RIGHT」的消息,就可以了。

  public void testMultiplyValues() {

  sendKeys(NUMBER_24+NUMBER_74+ " DPAD_RIGHT ENTER");

  String mathResult = result.getText().toString();

  assertTrue("Multiply result should be " + MULTIPLY_RESULT + " but was "

  + mathResult, mathResult.equals(MULTIPLY_RESULT));

  }

  步驟14 在模擬器中運行單元測試

  運行單元測試的方法很簡單,滑鼠右鍵項目,在彈出的菜單中選擇「Debug ASàAndroid JUnit Test」即可,運行結果如下兩圖所示:


 


  其中紅色的表示測試沒辦法通過,綠色的條狀表示測試已經通過。

  步驟15 Android中對屏幕顯示的單元測試

  在Android 的單元測試中,還可以針對界面的顯示位置等進行單元測試。比如我們在Eclipse時開發採用的界面模擬器是在800*480的模式下的,但如果在其他尺寸規格的行動裝置上是否能正常運行呢?這就需要對界面設置部分進行單元測試了。

  我們另外創建一個單元測試用例,用前文所講的方法新建立一個名為LayoutTests的單元測試用例,如下圖:


  並編寫如下代碼:

package com.mamlambo.article.simplecalc.test;

  import android.test.ActivityInstrumentationTestCase2;

  import android.view.View;

  import android.widget.Button;

  import com.mamlambo.article.simplecalc.MainActivity;

  import com.mamlambo.article.simplecalc.R;

  public class LayoutTests extends ActivityInstrumentationTestCase2 {

  private Button addValues;

  private Button multiplyValues;

  private View mainLayout;

  public LayoutTests() {

  super("com.mamlambo.article.simplecalc", MainActivity.class);

  }

  protected void setUp() throws Exception {

  super.setUp();

  MainActivity mainActivity = getActivity();

  addValues = (Button) mainActivity.findViewById(R.id.addValues);

  multiplyValues = (Button) mainActivity

  .findViewById(R.id.multiplyValues);

  mainLayout = (View) mainActivity.findViewById(R.id.mainLayout);

  }

  }

 

  這裡,分別獲得了加法按鈕和乘法按鈕的實例。接下來,增加一個testAddButtonOnScreen

  的方法,以測試按鈕的位置是否正確。在這個方法中,首先你要決定屏幕的大小。有很多方

  法去檢測屏幕的大小,比如用getWidth()和getHeight()方法,當然在考慮尺寸時,還必須考

  慮象標題欄,狀態欄等所佔用的位置大小。下面是其代碼:

public void testAddButtonOnScreen() {

  int fullWidth = mainLayout.getWidth();

  int fullHeight = mainLayout.getHeight();

  int[] mainLayoutLocation = new int[2];

  mainLayout.getLocationOnScreen(mainLayoutLocation);

  int[] viewLocation = new int[2];

  addValues.getLocationOnScreen(viewLocation);

  Rect outRect = new Rect();

  addValues.getDrawingRect(outRect);

  assertTrue("Add button off the right of the screen", fullWidth

  + mainLayoutLocation[0] > outRect.width() + viewLocation[0]);

  assertTrue("Add button off the bottom of the screen", fullHeight

  + mainLayoutLocation[1] > outRect.height() + viewLocation[1]);

  }

 

  在各類尺寸的模擬器上運行,可以得到如下結果所示的測試結果:

  480x800, portrait 模式 (通過)

  800x480, landscape mode (失敗)

  320x480, portrait mode (失敗)

  480x320, landscape (失敗)

  480x854, portrait mode (通過)

  854x480, landscape mode (失敗)?

  大家可以思考下為什麼有的測試用例成功有的失敗。

  總結

  本文講解了如何使用junit配合Android的應用進行單元測試及詳細步驟,以及如何在

  Junit測試Android時的小技巧。可以看到,在設計完應用後應該編寫單元測試用例,測試用

  例越多和越詳細,則對程序的正確性提高越有好處。

相關焦點

  • Android單元測試與日誌輸出
    使用單元測試可以保證我們開發的應用質量, 一般我們開發完業務層後對業務層進行測試,確保業務層不會出現bug,對業務層通過之後控制層就可以調用業務層 完成所需的功能。本文引用地址:http://www.eepw.com.cn/article/201609/305199.htm以前做Java開發的時候用junit進行測試,利用System.out.println() 方法在控制臺進行列印,下面我來講講如何對Android應用進行 單元測試以及日誌輸出。1.
  • SpringBoot對單元測試支持、常用單元測試功能使用實例
    SpringBoot 單元測試Spring Boot 提供了許多註解和工具幫助開發人員測試應用,在其官方文檔中也用了大量篇幅介紹單元測試的使用。在谷歌每周的 TGIF (ThanksGod, it's Friday)員工大會中有一項就是 宣布-周單元測試競賽獲勝的工程師。
  • Android單元測試 - Sqlite、SharedPreference、Assets、文件操作...
    既然如此重要,對這塊代碼進行測試,也成為單元測試的重中之重了。 筆者在學會單元測試前,也像大多數人一樣,寫好了sql代碼,運行app,報錯了....檢查代碼,修改,再運行app....這真是效率太低了。有了單元測試做武器後,我寫DAO代碼輕鬆了不少,不擔心出錯,效率也高。 常用的數據儲存有:sqlite、SharedPreference、Assets、文件。
  • JUnit 5測試引擎提示 junit-vintage 異常
    在 Spring 項目中運行測試的時候,得到錯誤:TestEngine with ID 'junit-vintage' failed to discover tests」 with Spring這個錯誤的原因是 JUnit 的引擎,使用了 junit-vintage 引擎。
  • Junit-jupiter api 和 engine
    我們都知道 JUnit 是用於進行單元測試的。但是 Junit 5 和 Junit 4 的區別比較大。很多時候你可能會遇到 Junit 引擎配置錯誤導致測試無法進行。junit-jupiter-apiJUnit 5 Jupiter API 的測試,你需要使用這個 API 來寫測試和進行擴展。
  • 從0到1上手JUnit5
    本文假定讀者有單元測試基礎,不會對單元測試的概念做過多的介紹,主要講解junit5的新功能用法,讓讀者快速上手Junit5。​如果你想了解單元測試的基礎概念可以閱讀文章:注意:建議大家使用文章中推薦的jdk、Eclipse、mvn以及 pom.xml進行配置,可以確保大家代碼的順利運行!
  • idea | junit4 整合
    本地的開發工程已經完全切到 idea 上,但單元測試跑的不順暢,今天決心重新徹底解決一次整個修復過程如下:1.配置pom文件<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId>
  • 2014 非常好用的開源 Android 測試工具
    在開發 Android 應用的時候要進行測試,現在市場上有大量的測試工具。本文主要是展示一系列的開源 Android 測試工具。每個工具都會有相應的簡短介紹,還有一些相關的資源。Android 測試工具列表是按照字母來排序的,最後還會介紹幾個不是特別活躍的 Android 測試相關的開源項目。
  • SpringBoot單元測試之一:基本操作
    》系列《SpringBoot單元測試》系列旨在通過一系列知識歸納和實戰,和讀者們一起提升在SpringBoot環境下的單元測試的技能;本篇概覽本文是《SpringBoot單元測試》系列的第一篇,咱們一起來寫幾個最簡單的單元測試類,了解如何測試Service層和Controller層,包括以下內容:
  • 使用全新 Android 模擬器工具進行持續測試
    Android 模擬器來快速測試修改過的應用,然後再提交代碼。當前使用的埠為 5555,我們需要收集更多反饋,並就如何最好地在不同容器間分配埠進行更深入的研究。先做一個安全說明: 使用遠程流時,一旦啟動服務,任何可以在 80/443 埠上連接到您的計算機的人都可以與模擬器進行交互。因此在公共伺服器上運行遠程流時請務必注意這一點!
  • 筆記:如何優雅的寫好單元測試
    ,通過單元測試我們很容易判斷我們的程序邏輯是否正確,它主要是對程序的一個一個函數進行測試。同時,通過單元測試也可以檢驗我們編寫的程序結構是否合理,可讀性是否強。也就是當別人拿到我們的這一份代碼的時候,是否可以很容易讀懂程序想要實現的功能,以及實現該功能的邏輯是否清晰,條理是否明確。當我們的單元測試沒辦法編寫或者很難編寫的時候,這個時候我們就需要對我們編寫的程序進行重構了,重構的過程就是將程序代碼進行解耦,使整個程序代碼的設計條理清晰,增強代碼的邏輯可讀性。
  • 單元測試框架 pytest 的使用
    pytest 是 python 的一種單元測試框架,與 python 自帶的 unittest 測試框架類似,但是比 unittest 框架使用起來更加方便,效率更高。pytest怎麼安裝安裝?>PyCharm 終端輸入:py.test結果如下圖,可以看出 pytest 測試了一項,即:test_pytest.py 文件下的 func 函數。
  • Android Banner開源庫使用介紹
    Banner圖這個功能,應該是很多APP都會有,這裡介紹的是一個個人使用起來比較方便,自由度比較高的一個開源庫,這個能讓我們在開發的過程中剩下不少時間。androidx.appcompat:appcompat:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.1' testImplementation 'junit:junit:4.12' androidTestImplementation
  • 單元測試,只是測試嗎?
    阿里妹導讀:推廣單元測試,僅僅達到單測覆蓋率是遠遠不夠的,我們還要學習寫"易於測試"的代碼,以及"好"的測試,這樣才能讓單測真正發揮作用。本文將分享作者關於單元測試的思考與實踐。文末福利:《阿里巴巴編碼規範》認證。
  • Android開發的單元測試
    本期活動主要圍繞「移動應用數據分析,移動開發單元測試,以及移動應用產品設計」主題展開。這是廈門移動開發者的一次本地聚會。活動中 還設計了形式豐富的技術交流環節,還有Lumia 800 Windows Phone 7真機體驗。我們邀請了嘉賓之一英睿信息技術總監傅雪峰為大家帶來了「Android開發的單元測試」的主題演講。
  • 軟體測試工具大全
    開發工具:java :eclipse 、myeclipse 、IDEA android :androidstudio 、eclipebanndle(eclipe+adt+android sdk) python :
  • 單元測試框架怎麼搭?來看看新版Junit5的這些神奇之處吧
    其實單測是開發人員必備技能,只不過很多開發人員開發任務太重導致調試完就不管了,沒有系統化的單元測試,單元測試在系統重構時能發揮巨大的作用,可以在重構後快速測試新的接口是否與重構前有出入。@BeforeAll:在每個單元測試方法執行前執行一遍(只執行一次)@DisplayName("商品入庫測試"):用於指定單元測試的名稱@Disabled:當前單元測試置為無效,即單元測試時跳過該測試@RepeatedTest(n):重複性測試,即執行n次@ParameterizedTest:參數化測試
  • Android單元測試 - 驗證函數參數、返回值的正確姿勢
    上一篇《Android單元測試 - Sqlite、SharedPreference、Assets、文件操作 怎麼測?》 講了一些DAO(Data Access Object)單元測試的細節。本篇講解參數驗證。 驗證參數傳遞、函數返回值,是單元測試中十分重要的環節。筆者相信不少讀者都有驗證過參數,但是你的單元測試代碼真的是正確的嗎?
  • 對Spring MVC接口進行Mock測試
    也有的使用Postman等工具進行測試,雖然在使用上沒有什麼問題,如果接口增加了權限測試起來就比較噁心了。所以建議在單元測試中測試接口,保證在交付前先自測接口的健壯性。今天就來分享一下胖哥在開發中是如何對Spring MVC接口進行測試的。
  • 單元測試實踐篇:Mock
    這類應用的單元測試不能像微服務化的應用一樣,可以方便的將整個 service 在本地 Run Test,但是依靠於日常開發部署環境的遠程 debug、日誌、Arthas上手Mock 框架能幫助我們 mock 待測試的類中使用到的外部服務依賴