6

我已经使用 PHP 和 JS 编写了一个 webapp,它现在可以工作,并决定我应该学习单元测试并在清理我的代码时立即实施它。

我对应该对什么进行单元测试感到困惑。我见过的每个 PHPUnit 教程都测试了 getter、setter、对数组中的项目进行计数。我正在处理的网站上有一个显示照片的页面。用户可以喜欢照片或将其添加到他的收藏夹。PHP 主要在站点中用作客户端运行主干.js 的 API 层。

我应该如何为这些功能编写单元测试?一个函数(如下所示)获取通过 AJAX 发送给它的 $_GET 数据,并将一些行插入到数据库中。它不包含任何 setter、getter 或计数任何东西,也不是一个类。它甚至应该进行单元测试吗?

我可以为这些功能编写的单元测试示例将非常棒!:)

/**
 * 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是否必须包含数据。我觉得应该有一个测试来检查这两个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);

}
4

2 回答 2

4

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

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

首先,我建议将它分成 3 个部分。

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

如果将其拆分,则第二个和第三个功能将变得可测试。

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

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

于 2012-08-11T11:42:06.187 回答