像这样的功能有单元测试吗?

时间:2012-08-10 01:17:31

标签: php unit-testing tdd phpunit

我已经使用PHP和JS编写了一个webapp,它现在正在运行,并决定我应该学习单元测试并在清理我的代码时实现它。

我对应该进行单元测试的内容感到困惑。每个PHPUnit教程我都见过测试getter,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是否必须包含数据。我觉得应该有一个测试来检查2 insert查询是否有效,但我也认为插入行的函数是由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);

}

2 个答案:

答案 0 :(得分:4)

首先,你应该制作一个“单位”进行测试。

您当前的实现将所有内容都放入一个函数中。这样的代码很难测试。

首先,我建议将其分为3个部分。

第一部分进程$_GET并组成一个内部表达式。 然后第二部分将其保存到数据库中。 最后,第三部分接收数据库中的对象,并呈现响应。

如果将其拆分,第二个和第三个函数将变得可测试。

这太天真了,但也许值得你迈出第一步。如果您有兴趣,请搜索MVC。

答案 1 :(得分: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,我发现它也非常适合在连续集成环境中使用。