تصویر پویا اسماعیلیان

در مجموع، تست‌های مختلفی برای کد وجود دارند که از مهم‌ترین آنها می‌توان به تست Unit و تست Functional اشاره کرد.  تست Unit برای صحت سنجی اجزاء کد استفاده می‌شود. به عبارت دقیق‌تر، در کدهای شی‌گرا برای تست Method ها و متغیر‌های کلاس‌ها، و در کدهای روالی، برای اعتبارسنجی توابع یا حتی متغیرهای عمومی استفاده می‌شود. تستی که در Drupal استفاده می‌شود از نوع Funtional است. در این تست بررسی می‌شود که آیا قطعه کدی که به Drupal وارد می‌شود (در اینجا، یک ماژول) آن‌گونه که انتظار می‌رود کار می‌کند یا نه؟. یعنی، در مقایسه با تست Unit، تست Functional به صورت کلی کد مورد نظر را بررسی می‌کند.

از فواید اصلی این ابزار در Drupal می‌توان به نظم بخشی به فرآیند تست، سهولت اشتراک‌گذاری آزمایش‌ها و از همه مهم‌تر حفظ کارایی یک قطعه کد در طول فرآیند تولید/نگه‌داری سایت اشاره کرد؛ چرا که با تغییرات آتی در ساختار کد و از دست رفتن تسلط برنامه‌نویس بر روی کد‌های قبلی امکان بروز خطاهای صعب‌العلاج! بالا می‌رود. به همین خاطر، در هنگام تولید کد، برنامه نویس می‌تواند با طراحی تست‌های هوشمندانه از بروز خطاهای احتمالی در آینده جلوگیری کند.

ماژول ساده‌ی زیر را در نظر بگیرید:

<?php

// $Id$

/**
 * @file
 * A module exemplifying Drupal coding practices and APIs.
 *
 * This module provides a block that lists all of the
 * installed modules. It illustrates coding standards,
 * practices, and API use for Drupal 7.
 */

//Tells Drupal aboth the block "list_modules"
/**
 * Implements hook_info().
 */
function first_block_info() {
  $blocks = array();

  $blocks['list_modules'] = array(
    'info' => t('A listing of all of the enabled modules.'),
    'cache' => DRUPAL_NO_CACHE,
  );
  return $blocks;
}

//Drupal assumes that this block has something to show so:
/**
 * Implements hook_block_view().
 */
function first_block_view($block_name = '') {
  if ($block_name == 'list_modules') {
    $list = module_list();//Drupal's function
    
    $theme_args = array('items' => $list, 'type' => 'ol');
    //using theme layer for formatting
    //theme returns the string of HTML
    $content = theme('item_list', $theme_args);
    
    $block = array(
      'subject' => t('Enabled Modules'),
      'content' => $content, //it's a formatted HTML
    );
    return $block;
  }
}

می‌خواهیم برای صحت کارکرد هر یک از توابع info و view دو تست بنویسیم. ابتدا یک فایل هم اسم ماژول و با پسوند .test را در پوشه‌ی ماژول ایجاد می‌کنیم. بدون ورود به مفاهیم شی‌گرایی، قالب کلی زیر را وارد می‌کنیم:

class FirstTestCase extends DrupalWebTestCase {

  public function getInfo() {
    return array(
      'name' => 'First module block functionality',
      'description' => 'Test blocks in the First module.',
      'group' => 'First', //group similar tests together under a heading
    );
  }

}

که اطلاعات لازم را به Drupal درباره‌ی این تست می‌دهد.

۱) در مورد تابع info، که هیچ ورودی نمی‌گیرد، می‌خواهیم تست کنیم که آیا آرایه‌ای که برمی‌گرداند وجود دارد؟ و اگر وجود دارد آیا اطلاعات تنها یک ماژول را برمی‌گرداند؟. برای این منظور تابع زیر را به داخل کلاس بالا اضافه می‌کنیم:

public function testBlockInfo() {
    //execute hook "first_block_info()" from module "first"
    $info = module_invoke('first', 'block_info');
    //check if it returns information for only 1 module
    $this->assertEqual(1, count($info), t('Module defines a block.'));
    //check if the list of modules is not empty
    $this->assertTrue(isset($info['list_modules']), t('Module list exists.'));
  }

۲) در مورد تابع view، که یک ورودی می‌گیرد، می‌خواهیم تست کنیم که آیا داده‌ی بازگشتی از جنس آرایه است؟ و اگر هست عنوان لیست با عنوان مورد انتظار یعنی "Enabled Modules" هم‌خوانی دارد؟. برای این منظور تابع زیر را نیز اضافه می‌کنیم:

 

public function testBlockView() {
    //invoke with input 'list_modules'
    $data =module_invoke('first', 'block_view', 'list_modules');
    //check if data structure is valid
    $this->assertTrue(is_array($data),
        t('Block returns renderable array.'));
    //check if subject is set correctly
    $this->assertEqual(t('Enabled Modules'),
        $data['subject'],
        t('Subject is set'));
  }

حال برای انجام آزمایش، در صفحه‌ی Drupal از قسمت Configuration، زیرقسمت Testing را انتخاب می‌کنیم. در صفجه‌ی جدید به دنبال First بگردید و جعبه‌ی آن را فعال کنید. در آخر دکمه‌ی run tests را در پایین صفحه بزنید. پس از چند ثانیه نتیجه‌ی تست قابل مشاهده است. می‌توانید یکی از اسامی را به اشتباه تغییر دهید و دوباره تست بگیرید تا با حالت خطا نیز آشنا شوید.

 

امیدوارم، این مکانیزم زیبا و خوش‌ساختار شما را برای صرف وقت در راستای تولید تست‌های مورد نظرتان تشویق کرده باشد :)

 

با آرزوی موفقیت ؛)

منبع: کتاب Drupal 7 Module Development سال ۲۰۱۰

طبقه بندی: 
برچسب ها: 

دیدگاه‌ها

تصویر محمدعلی اکبری

محمدعلی اکبری

سلام، ممنون بابت آموزش خوب و بیان جذابتون.

متدهای testBlockInfo و testBlockView از قبل تعریف شده هستند؟ برای اینکه بقیه متدها رو برای تست اجزای دیگه ماژول داشته باشیم باید از کجا پیداشون کنیم؟

تصویر پویا اسماعیلیان

پویا اسماعیلیان

با سلام،

 در این کلاس، هر تعداد تابعی که لازم است با اسم‌های قراردادی می‌توانید اضافه کنید و جای دیگری نیاز به تعریف نیست. مثلا، می‌توانید تابع دیگری (مانند tst1234) بنویسید که از متد x در ماژولِ همنام (اینجا، ماژولِ first) خروجی بگیرد به متد y ورودی بدهد و دوباره خروجی بگیرد، همچنین، خروجی hook_block_view را چک کند و در نهایت بنا به خروجی‌های گرفته شده پیغام‌های مختلفی را چاپ کند.

افزودن نظر جدید