2012-08-10 59 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,我发现它也非常适合在持续集成环境中使用。