圈複雜度和可測試性

  1. 最好用的C++圈複雜度分析工具:pip install lizard,沒想到它解析C++的函數塊超級快,可以用來作爲建立進一步的代碼片分析的基礎,完勝其他所有工具。
  2. 我花了1天多將一個C++模塊測試覆蓋率做到100%,對於代碼如何才具有良好可測試性有了直觀的經驗,從測試的角度看代碼的設計是否簡潔是一個非常合理的角度。
  3. 如果代碼的可測試性很好,那麼AI也能非常容易的處理它,可見未來的代碼,不是要寫的複雜,就是寫的直接簡潔,實際上就是要保持線性。

如何將一個難以測試的類改進爲易於測試的類?

例子1,切分輔助的純函數

讓這個類的構造依賴的參數簡單,簡單不一定是參數個數少,而是這些參數的構造本身的依賴不要有太多深度。

以前有一個痛點問題是,一個類的內部有一些成員變量不好修改,於是不好再測試的時候控制函數內部的分支行爲。解決方式是:將控制複雜行爲的函數實現拆分,拆分爲調用幾個輔助函數,這幾個輔助函數是純函數,依賴的參數都通過函數參數傳遞(即使這個參數是類成員變量就有的),這樣這個輔助函數就容易被測試,因爲是一個純函數,因爲都通過函數參數傳遞狀態。
例子:

class A{
public:
  void run(){
      if(config.enable_xxx){
         do_something();
      }
  }
  void dosomthing(){
    status.value = ...
  }
private:
  Config config;
  Status status;
}

這個run就不好測試,因爲測試方不好控制Config的狀態。修改如下:

class A{
public:
  void run(){
    do_something(config, status);
  }

  bool do_somthting(const Config& config, const Status& status){
    if(!config.enable_xxx){
       return false;
    } 
    status.value = ...
  }
private:
  Config config;
  Status status;
}

這個時候就可以對 do_something 做測試了,因爲do_somthting依賴的對象,和修改的對象,都是通過函數參數傳遞的,是一個純函數。那麼測試函數和A::run 對於do_somthting來說都是同等的訪問能力。

例子2: 處理內部的返回值問題

下面的類,內部對於某個API請求對結果做處理,但是測試方不易於控制API請求的結果,不好測試到對應分支。

class A{
public:
   void run(){
       xxx v;
       bool ret = receiver.pop(v);
       if(ret){
         ....
       }
   }
}

解決方式是把獲取數據和處理數據完全的分開成兩個部分:

class A{
public:
   void run(){
     xxx v;
     bool ret = receiver.pop(v);
     on_receive_v(ret, v);
   }
   bool on_receive_v(bool ret, const xxx& v){
       if(!ret){
         return false;
       }
       ...
   } 
}

這樣分支跑到 on_receive_v 裏面去,而 on_receive_v 是一個易於通過參數控制分支測試的函數。

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