2012-08-10 61 views
6

我已經寫了一個使用PHP和JS的web應用程序,現在正在工作,並決定我應該學習單元測試,並在清理代碼時執行它。像這樣的函數有單元測試嗎?

我很困惑應該單元測試什麼。我見過的每個PHPUnit教程都是測試getters,setters,對數組中的項進行計數。我正在處理的網站上有一個顯示照片的頁面。用戶可以喜歡一張照片或將其添加到他的收藏夾。 PHP主要在站點中作爲客戶端運行backbone.js的API層使用。

我應該如何爲這些函數編寫單元測試?一個函數(如下所示)抓取通過AJAX發送給它的$ _GET數據,並在數據庫中插入一些行。它不包含任何setter,getters,或計數任何東西,而不是一個類。它應該甚至有單元測試嗎?

我可以爲這些函數編寫一個單元測試的例子將非常棒! :)

/** 
* Create new Set and add item to it 
* @return void 
*/ 
public function action_create_set() { 
    // Get data from user 
    $user_id = Input::get('user_id'); 
    $post_id = Input::get('post_id'); 
    $set_name = Input::get('set_name'); 

    // Create new set 
    $data = array(
     'user_id' => $user_id, 
     'name' => $set_name 
    ); 
    $set_id = DB::table('sets')->insert_get_id($data); 

    // Add item to newly created set 
    DB::query("INSERT IGNORE INTO posts_sets (post_id, set_id, user_id) 
     VALUES ($post_id, $set_id, $user_id)"); 

    // Change `created_at` & `updated_at` col of 'sets' 
    $data = array(
     'created_at' => DB::raw('NOW()'), 
     'updated_at' => DB::raw('NOW()') 
     ); 
    DB::table('sets') 
     ->where('id', '=', $set_id) 
     ->update($data); 
} 

對於第一個功能,我的印象是一個測試可寫檢查那些3個變量$user_id, $post_id, $set_name必須包含的數據。我覺得應該有一個測試來檢查查詢是否工作,但我也認爲插入行的函數是由PHP框架提供的,並且已經過徹底測試,因此不需要進一步的單元測試。

另一個猜測是測試應該爲函數提供3個變量,然後檢查新行是否已經插入到2個表中,但是這不會被認爲是一個集成測試嗎?


這裏的一個函數,它從通過AJAX的用戶輸入,然後將結果返回JSON格式。 PHPUnit應該處理這種API函數嗎?還是應該在客戶端進行單元測試?

/** 
* Get items Liked by user 
* @return array 
*/ 
public function action_likes() { 

    $user_id = Input::get('user_id'); 

    $likes = DB::table('likes') 
       ->join('posts', 'posts.id', '=', 'likes.post_id') 
       ->where('likes.user_id', '=', $user_id) 
       ->get(); 

    return json_encode($likes); 

} 

回答

4

首先,你應該做一個「單位」進行測試。

您當前的實現將所有內容放入函數中。這樣的代碼很難測試。

起初,我建議將它分成3部分。

第一部分進程$_GET並組成一個內部表達式。然後第二部分將它保存到數據庫中。 最後,第三部分接收數據庫中的對象,並呈現響應。

如果將其分開,第二個和第三個函數將變爲可測試的。

這太天真了,但也許值得作爲你的第一步。如果你有興趣,請搜索MVC。

1

另一種猜測是測試應提供3個變量的 功能,然後檢查新行是否已經被插入到 2表,但難道不這纔算是一個集成測試?

一般注意事項:當你開始學習一般的單元測試和自動化測試,你會很快認識到,像「單元測試」和「集成測試」而言實際上是相當相對的,非常依賴於上下文的。

從你對action_create_set函數的描述看來,你可以把它當作你web api層的一部分。如果你決定爲這個圖層編寫測試,那麼是的,測試這個函數是否真正以正確的方式轉換你的數據庫是個好主意。

它是單元測試嗎?那麼有人可能會認爲答案是否定的,因爲這個函數做的「太多」事情(從HTTP請求轉換數據,進行數據庫調用,以及通過僞造http請求來測試它,這通常涉及整個http處理堆棧)。

另一方面,您正在測試web api的一個單一功能,該應用程序在應用程序的業務邏輯方面具有單一且明確定義的責任。這將是積極答案的一個論據。

我個人比較喜歡後者,但在一天結束時它並不重要。

這是一個函數,它接受用戶通過AJAX的輸入,然後以JSON格式返回 結果。 PHPUnit是否應該處理這種API 函數?還是應該在客戶端進行單元測試?

它依賴於情況。從測試自動化純粹主義者的角度來看,完美的解決方案將是對雙方進行測試。

服務器端測試,應說明並測試如何在不同情況下的action_likes函數表現:

  • 它返回空集時沒有可用的數據?
  • 如果user_id缺失或格式不正確,會發生什麼情況?
  • 在典型場景中返回什麼?

每個測試都應該以數據庫中的一些預設數據開始,並檢查返回的JSON的內容。這樣你正在測試你的服務器API層。

但測試客戶端代碼也是有意義的。大多數情況下,從ajax調用成功接收數據應該會有一些副作用。

您可以測試例如應該處理接收數據的適當回調被實際調用,或者某些數據結構會相應地作出反應。

在這種測試中,您並未與真實服務器進行交互,但您正在使用爲此設計的js庫嘲笑AJAX請求和響應。其中有很多。我目前的偏好包括buster.js,我發現它也非常適合在持續集成環境中使用。