把斷言(Assert)發揮的淋漓精緻,提高代碼的健壯性

目錄

  • 一、什麼是斷言,什麼情況下應該使用androidAssert?

  • 二、在release版本中移除斷言代碼,只在debug中保留

  • 三、集成AndroidAssert庫

  • 總結

一、什麼是斷言,什麼情況下應該使用androidAssert?

通常斷言(assert)是在單元測試時,用來校驗函數返回的結果。在自動化測試用來校驗程序運行結果。

但是我們接下來要討論的並不是單元測試中使用斷言,而是在項目業務代碼中使用斷言

我們一起來看幾個,大家非常熟悉的例子。這些情況下使用斷言會讓代碼更加優雅,更加健壯。

例子1,writeFile

/**
 * 我們希望只在子線程中調用writeFile(),主線程中調用可能會導致ui卡頓或者anr。
 *
 * 如果在主線程調用writeFile(),我們打印日誌警告開發者
 */
public void writeFile() {
    //主線程,打印日誌警告開發者
    if(!ThreadTypeUtil.isSubThread()){
        Log.e(TG, "you should call writeFile at sub thread");
    }
    // write file ...
}

當出現有開發人員,嘗試在主線程中調用writeFile()方法時,我們通過 日誌警告 ,開發者。但是,日誌提示很弱,往往會被開發者忽略掉。

於是我們改良了下代碼:

public void writeFile() {
    //debug版本,主線程中調用 writeFile ,直接拋出異常中斷程序運行
    if(!ThreadTypeUtil.isSubThread()){
        if(BuildConfig.DEBUG) {
            throw new RuntimeException("you should call writeFile at sub thread");
        }
    }
    // write file ...
}

當程序員企圖在主線程中調用writeFile(),在debug模式下,我們直接拋出異常,讓程序崩潰。以中斷他的開發。強制他優化代碼。

我們引入斷言庫,繼續改造代碼,讓代碼更簡潔漂亮:

/**
 * 在debug模式,下將直接拋出異常 AssertionFailedError。讓開發者
 * 在release模式,不會拋出異常,會正常執行writeFile()函數。
 */
public void writeFile() {
    AndroidAssert.assertSubThread();
    // write file ...
    Log.i(TG, "writeFile...");
}

AndroidAssert.assertSubThread()斷言爲子線程的意思是,斷定當前線程一定是子線程,如果不是,那麼拋出異常 AssertionFailedError。

AndroidAssert是一個開源庫,使用前需要引入這個開源庫,後面會講。

繼續優化

只有在debug版本,AndroidAssert 類,纔有用;

在release版本的apk上,能否把 AndroidAssert 相關調用的代碼刪除?

我們先挖個坑,把例子講完,再將release刪除代碼的方法。大家先忍一忍。

例子2,updateUI

/**
 * 在release版本,如果在子線程中調用updateUI,我們直接return,不做ui更新操作。
 * 但是在debug版本,如果在子線程中調用updateUI,直接出異常,讓開發者發現異常調用並解決。
 */
public void updateUI() {
    boolean isMainThread = ThreadTypeUtil.isMainThread();
    if (!isMainThread) {
        AndroidAssert.fail("updateUI must be called at main thread");
        return;
    }
    //update ui ....
    Log.i(TG, "updateUI...");
}

例子3,startMainActivity

/**
 * 斷言context爲非空,如果爲null,debug模式下拋出異常 AssertionFailedError
 */
public void startMainActivity(Context context) {
    AndroidAssert.assertNotNull("context must not null", context);
    if (context == null) {
        return;
    }
    //startMainActivity...
    Log.i(TG, "startMainActivity...");
}

二、我們繼續改良,例子1,在release版本中移除斷言代碼,只在debug中保留

只有在debug版本,AndroidAssert 類,纔有用;

在release版本的apk上,能否把 AndroidAssert 相關調用的代碼刪除?

或者說打包的時候,把 AndroidAssert 相關的調用的代碼 和 AndroidAssert類的代碼 全部刪除,再打包。

於是我想到了proguard。

在proguard中添加如下配置即可:

# -dontoptimize ## 注意注意注意,proguard中配置dontoptimize;將會導致proguard不做代碼優化,不會刪除AndroidAssert類
-assumenosideeffects class com.it.uncle.lib.util.AndroidAssert{
    public *;
}

注意,注意,千萬注意:不能開-dontoptimize,開了assumenosideeffects將失效

對用法有疑惑的可以,看下這篇blog:https://blog.csdn.net/jiese1990/article/details/21752159

以及官方wiki:https://www.guardsquare.com/en/products/proguard/manual/usage#assumenosideeffects

校驗assumenosideeffects是否生效

  1. 反編譯debug和release包對比。

比如,我們demo裏的TestActivity

public class TestActivity extends MainActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);

        AndroidAssert.assertNotNull(getIntent());
    }
}

我們分別反編譯debug和release包,找到TestActivity類的代碼對比:

  1. 配置成功後,打包在mapping中搜索:com.it.uncle.lib.util.AndroidAssert

proguard未配置 -assumenosideeffects 的mapping.txt文件

proguard配置了 -assumenosideeffects 的mapping.txt文件:

三、集成AndroidAssert庫

  • gradle

    implementation 'com.ituncle:android-assert:0.0.2'
    
  • 初始化sdk,儘早調用,建議在Application#onCreate的時候調用。

//初始化----斷言失敗時,是否拋出異常
AndroidAssert.enableThrowError(BuildConfig.DEBUG);//我們設置爲debug模式下,斷言失敗才拋出異常
  • 添加proguard,在開啓混淆的版本中,移除AndroidAssert的代碼

    # -dontoptimize ## 注意注意注意,proguard中配置dontoptimize;將會導致proguard不做代碼優化,不會刪除AndroidAssert類
    -assumenosideeffects class com.it.uncle.lib.util.AndroidAssert{
        public *;
    }
    



總結

android-assert是一個非常簡單輕量的android斷言庫。類似於junit的Assert類。

android-assert不是用來寫測試用例的,可以直接在項目代碼中使用他。

在debug模式下,斷言失敗將會拋出斷言異常 AssertionFailedError,在release模式下,將不會拋出異常。

更多關於android-assert,看github文檔:https://github.com/AITUncle/AndroidAssert

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章