defect pluginهای TestRail برای اتصال TestRail به ابزارهای third-party ردیابی bug و issue مفید هستند. TestRail اسکریپتهای plugin آمادهای دارد که آن را با بسیاری از ابزارهای محبوب integrate میکنند. با این حال، defect pluginهایی که همراه TestRail ارائه میشوند برای کار با تنظیمات استاندارد ابزارهای defect tracking طراحی شدهاند و میتوانید آنها را مطابق نیاز خود سفارشی کنید.
اگر ابزار defect tracking خود را سفارشی کردهاید، مثلاً custom fieldهای اجباری جدید اضافه کردهاید، یا میخواهید رفتار defect integration را تغییر دهید، میتوانید defect pluginها را سفارشی کنید یا حتی pluginهای جدید بسازید. سفارشیسازی defect pluginها یا ساخت plugin جدید میتواند در سناریوهای زیر مفید باشد:
- ابزار defect tracking خود را طوری تنظیم کردهاید که به custom fieldهای بیشتری نیاز داشته باشد و میخواهید این فیلدها را به Push Defect dialog اضافه کنید
- میخواهید رفتار defect pluginهای پیشفرض را تغییر دهید؛ مثلاً user mapping اضافه کنید، اطلاعات بیشتری به bug reportهای ارسالشده اضافه کنید، و موارد مشابه.
- از یک ابزار سفارشی یا ابزاری استفاده میکنید که هنوز پشتیبانی نمیشود و میخواهید برای آن integration بسازید.
این مقاله معماری پایه defect pluginها و روش سفارشیسازی آنها را توضیح میدهد. همچنین یک صفحه نمونههای defect plugin داریم که بهصورت عملی نشان میدهد چطور فیلدهای جدید را به Push Defect dialog اضافه کنید و چطور قابلیت user mapping را به یک defect script بیفزایید.
#
اگر defect plugin خودتان را نوشتهاید و میخواهید آن را با کاربران دیگر به اشتراک بگذارید، میتوانید در repository عمومی TestRail Customizations GitHub repository مشارکت کنید.
شروع کار #
defect pluginها با PHP توسعه داده میشوند و برای سفارشیسازی یا ساخت defect plugin خودتان باید آشنایی پایهای با PHP داشته باشید. اگر سؤال مشخصی دارید، میتوانید با تیم پشتیبانی Gurock Software تماس بگیرید.
هنگام راهاندازی application، TestRail در دو directory بهدنبال defect pluginها میگردد. directory اول همان جایی است که TestRail pluginهای پیشفرض داخلی خود را هم نگه میدارد. هرگز اسکریپتهای plugin را در این directory اضافه یا ویرایش نکنید، چون هنگام update کردن TestRail این فایلها بازنویسی میشوند:
<TestRail>/app/plugins/defects
اسکریپتهای plugin جدید یا تغییر دادهشده را همیشه باید در directory مخصوص defect pluginهای سفارشی قرار دهید:
<TestRail>/custom/defects
فایلهای plugin #
defect plugin یک PHP script ساده است که classی را پیادهسازی میکند که TestRail برای ارتباط با ابزار defect tracking از آن استفاده میکند. برای سفارشیسازی یا ساخت defect plugin خودتان، میتوانید یک اسکریپت آماده را از application directory بالا به directory مخصوص defect pluginهای سفارشی کپی کنید و نام فایل را تغییر دهید. همچنین میتوانید کار را با skeleton script زیر شروع کنید.
برای مثال، اگر میخواهید Jira defect plugin در TestRail را سفارشی کنید، فایل را از <TestRail>/app/plugins/defects به <TestRail>/custom/defects کپی کنید. همچنین باید نام فایل را تغییر دهید، چون TestRail از نام فایل defect plugin بهعنوان شناسه یکتای آن یا class identifier استفاده میکند. برای مثال، میتوانید نام فایل را به Jira_ExampleInc.php تغییر دهید تا شامل نام سازمان شما یا نام ابزار سفارشیای باشد که میخواهید TestRail را با آن integrate کنید. در بخش بعدی میبینید چطور نام defect class را با نام فایل هماهنگ کنید.
مبانی plugin #
defect plugin یک PHP class ساده است که methodهای مشخصی را پیادهسازی میکند تا TestRail برای ارتباط با ابزار defect tracking آنها را فراخوانی کند. TestRail از نام فایل script بهعنوان شناسه یکتای script استفاده میکند. نام plugin class باید بر اساس نام فایل باشد. برای مثال، اگر نام فایل plugin script Jira.php باشد، نام plugin class باید Jira_defect_plugin باشد.
هر defect plugin class باید Defect_plugin base class مربوط به TestRail را extend کند. skeleton class زیر همه methodهای پایه را پیادهسازی میکند و methodها و argumentهای اصلی را توضیح میدهد.
// MyPlugin.php
class MyPlugin_defect_plugin extends Defect_plugin
{
// Get Meta
//
// Expected to return meta data for this plugin such as Author,
// Version, Description and supported plugin capabilities.
public function get_meta()
{
}
// Validate Config
//
// Validates the plugin configuration that is entered in the site
// or project settings. Expected to throw a ValidationException
// in case the passed configuration does not validate.
public function validate_config($config)
{
}
// Configure
//
// Passes the configuration for the plugin as specified in the
// site or project settings (as string).
public function configure($config)
{
}
// Prepare Push
//
// Signals if the plugin requires/supports a form to submit the
// defect. Returns 'false' to signal that no form is required.
// Otherwise the plugin should return the form description that
// is used to render the form and display it to the user.
public function prepare_push($context)
{
}
// Prepare Field
//
// Called for each field of the push form to gather the field
// data for the form. The plugin can return default values or
// available options for the field (in case of a dropdown
// box, for example), among other values.
public function prepare_field($context, $input, $field)
{
}
// Validate Push
//
// Called before the actual push attempt is processed (in case
// the plugin uses a custom form). Useful for adding custom
// validation functionality for the form that is not covered by
// TestRail itself. Expected to throw a ValidationException in
// case the passed input of the custom form does not validate.
public function validate_push($context, $input)
{
}
// Push
//
// Executes the actual push request by adding a new case to the
// defect tracker. Expected to return the new defect ID (as
// string or integer).
public function push($context, $input)
{
}
// Lookup
//
// Looks up the defect/issue/case with the given ID and returns
// its properties as key/value array. The following return values
// are required:
//
// id: The ID of the defect (usually the same as the
// passed ID)
// title: The title/summary of the defect
// status_id: The status ID of the defect. Possible values
// are:
// - GI_DEFECTS_STATUS_OPEN
// - GI_DEFECTS_STATUS_RESOLVED
// - GI_DEFECTS_STATUS_CLOSED
// status: The status as text
//
//
// The following properties are optional:
//
// url: The full HTTP url to view the defect
// description: The description of the defect (supports HTML,
// the plugin is responsible for providing well-
// formed and valid HTML and must escape data
// that is not expected to be rendered as HTML).
// attributes: A key/value list of additional attributes.
// The value also supports HTML with the same
// implications as for the description.
public function lookup($defect_id)
{
}
}
با این حال، همیشه لازم نیست همه methodها را کامل پیادهسازی کنید. defect pluginها در حال حاضر دو قابلیت دارند: ارسال defectها به یک application خارجی و جستوجوی اطلاعات defect. بسته به pluginی که میخواهید بنویسید و بسته به context، ممکن است پیادهسازی فقط یکی از این قابلیتها کافی باشد.
برای مثال، اگر بخواهید pluginی پیادهسازی کنید که به testerها اجازه دهد از طریق Push dialog ایمیل ارسال کنند، نیازی به پیادهسازی قابلیت lookup نیست. به همین شکل، اگر ابزار defect tracking شما امکان بازیابی اطلاعات defect را میدهد اما ترجیح میدهید از فرم bug report همان defect tracker استفاده کنید، لازم نیست قابلیت push را پیادهسازی کنید.
defect pluginها در کل انعطافپذیر هستند. برای مثال، همه defect pluginهایی که در حال حاضر همراه TestRail ارائه میشوند یک dialog نمایش میدهند تا testerها بتوانند bug report واردشده را سفارشی کنند، اما داشتن dialog همیشه ضروری نیست. defect plugin میتواند بهجای آن، bug report را بدون دخالت کاربر و بهصورت خودکار در background ارسال کند.
ساخت plugin خودتان #
این بخش شما را در ساخت اولین defect plugin راهنمایی میکند و methodها و الگوهای رایج مختلف plugin را توضیح میدهد. حتی اگر نمیخواهید plugin خودتان را از صفر بسازید و فقط قصد دارید یک plugin موجود را سفارشی کنید، این بهترین راه برای آشنایی با سازوکار داخلی pluginها است. در اینجا یک defect plugin جدید برای ابزار خیالی bug tracking به نام Bugs میسازیم و بخشهای بعدی مراحل ساخت plugin جدید را توضیح میدهند.
قبل از شروع کار با plugin جدید، مهم است بدانید که TestRail همه stringها و متنها را با encoding UTF-۸ انتظار دارد و خودش هم با همین encoding ارائه میکند. یعنی همه stringها و متنهایی که به TestRail برمیگردانید یا از TestRail دریافت میکنید باید با UTF-۸ encode شده باشند. این موضوع بهخصوص هنگام پردازش کاراکترهای غیرغربی مهم است، اما برای کاراکترهای خاص غیر ASCII و موارد مشابه هم باید آن را در نظر بگیرید.
ایجاد فایل #
اولین قدم برای ساخت یک defect plugin جدید، ایجاد خود فایل script است. در این مثال نام فایل را Bugs.php میگذاریم و آن را در directory مخصوص defect pluginهای سفارشی TestRail قرار میدهیم (<TestRail>/custom/defects). اگر میخواهید از یک defect plugin موجود استفاده کنید، همه defect pluginهای پیشفرض با source code کامل ارائه میشوند و در <TestRail>/app/plugins/defects directory قرار دارند. حتماً آن را به directory مخصوص defect pluginهای سفارشی کپی کنید و نامش را تغییر دهید. defect plugin پایه ما برای Bugz به این شکل است. توجه کنید که تگ PHP را نمیبندیم <?php تگ آغازین را در انتهای فایل قرار دهید؛ این یک ترفند است تا از ایجاد خطهای خالی در انتهای فایل جلوگیری شود، چون این خطها ممکن است خروجی headerهای PHP را به هم بزنند:
class Bugs_defect_plugin extends Defect_plugin
{
}
برگرداندن metadata #
اولین چیزی که باید پیادهسازی کنیم، get_meta method است. این method چند مورد را درباره plugin به TestRail اعلام میکند؛ مثل نام نویسنده، نسخه plugin، قابلیتهای پشتیبانیشده و جزئیات configuration. برای این کار، method فقط یک array شامل این جزئیات برمیگرداند، مانند نمونه زیر:
{
return array(
'author' => 'Example Inc.',
'version' => '1.0',
'description' => 'Bugs defect plugin for TestRail',
'can_push' => false,
'can_lookup' => false,
'default_config' =>
"; Please configure your Bugs connection below\n" .
"[connection]\n" .
"address=http:///\n" .
"user=testrail\n" .
"password=secret"
);
}
در اینجا، can_push و can_lookup properties اهمیت ویژهای دارند. این propertyها به TestRail میگویند defect plugin کدام قابلیتها را پیادهسازی کرده است. با اینکه در حال حاضر فقط قابلیتهای Push و Lookup وجود دارند، ممکن است در نسخههای آینده TestRail قابلیتهای جدیدی هم اضافه شود.
default_config property هم در اینجا قابل توجه است. defect pluginها را میتوان در TestRail بهصورت سراسری از بخش Administration > Site Settings یا برای هر project بهصورت جداگانه از بخش Administration > Projects پیکربندی کرد. وقتی administrator یک plugin را پیکربندی میکند، configuration پیشفرضی که در default_config مشخص شده است، داخل فیلد متنی configuration بارگذاری میشود.
Configuration #
یک defect plugin معمولاً به چند setting برای configuration نیاز دارد؛ مثل آدرس defect tracker، username و password، و گزینههای مشابه. وقتی administrator یک defect plugin را در TestRail پیکربندی میکند، تنظیمات configuration را در یک فیلد متنی وارد میکند. این روش به pluginها اجازه میدهد format مخصوص خودشان را برای configuration داشته باشند، چون فیلد متنی از notationهای مختلفی مثل گزینههای INI، XML و موارد مشابه پشتیبانی میکند.
defect pluginهای پیشفرض TestRail برای تنظیمات configuration از notation فایل INI استفاده میکنند؛ بنابراین [sections] و name=value pairها برای مشخص کردن settingها به کار میروند. از آنجا که TestRail methodهایی برای خواندن این نوع گزینههای configuration دارد، معمولاً بهتر است از notation مربوط به INI استفاده کنید.
وقتی administrator یک plugin را پیکربندی میکند، TestRail از plugin میخواهد تنظیمات configuration واردشده را اعتبارسنجی کند. چون TestRail از settingهای ضروری configuration، یا حتی format این تنظیمات، اطلاعی ندارد، خود defect plugin باید بررسی کند که همه settingهای لازم مشخص شده باشند. برای این کار، TestRail validate_config method را هر بار که administrator بخواهد configuration را تغییر دهد فراخوانی میکند:
public function validate_config($config)
{
$ini = ini::parse($config);
// Check if the [connection] section exists
if (!isset($ini['connection']))
{
throw new ValidationException('Missing [connection] group');
}
// Check if the required values exist
$keys = array('address', 'user', 'password');
foreach ($keys as $key)
{
if (!isset($ini['connection'][$key]) ||
!$ini['connection'][$key])
{
throw new ValidationException(
"Missing configuration for key '$key'"
);
}
}
$address = $ini['connection']['address'];
// Check whether the address is a valid url (syntax only)
if (!check::url($address))
{
throw new ValidationException('Address is not a valid url');
}
}
method بالا بررسی میکند که [connection] section وجود داشته باشد و این section شامل keyهای address ، user و password باشد. همچنین بررسی میکند که key مربوط به address یک URL معتبر داشته باشد؛ این کار از طریق check::url routine انجام میشود. همچنین توجه کنید که ini module مربوط به TestRail در ابتدای method برای parse کردن تنظیمات configuration استفاده میشود. اگر method مشکلی در configuration پیدا کند، مثل نبودن یک key یا نامعتبر بودن یک value، یک exception از نوع ValidationException ایجاد میکند. سپس TestRail پیام خطا را به administrator نشان میدهد.
بعد از پیکربندی settingها، plugin باید بتواند به این settingها دسترسی داشته باشد. TestRail بهصورت خودکار configure method را هر بار که defect class ساخته میشود فراخوانی میکند. برای مثال، قبل از اینکه TestRail از یک defect plugin بخواهد یک defect ID را lookup کند، configure method را فراخوانی میکند تا همه تنظیمات configuration لازم را در اختیار plugin قرار دهد. plugin مسئول است تا وقتی instance فعال است این settingها را نگه دارد، تا هنگام فراخوانی methodهای اصلی به آنها دسترسی داشته باشد. معمولاً plugin برای این کار settingها را در یک instance variable ذخیره میکند:
public function configure($config)
{
$ini = ini::parse($config);
$this->_address = str::slash($ini['connection']['address']);
$this->_user = $ini['connection']['user'];
$this->_password = $ini['connection']['password'];
}
این method تنظیمات configuration را دوباره از طریق ini module parse میکند و آنها را در instance variableها یا fieldها ذخیره میکند. بنابراین برای دسترسی به آدرس defect tracker در فراخوانیهای بعدی methodها، plugin میتواند بهسادگی به $this→_address.
جستجوی defectها #
ابتدا قابلیت lookup برای defectها را مرور میکنیم، چون پیادهسازی آن از قابلیت push defect سادهتر است و راه خوبی است برای اینکه با نحوه کار defect pluginها بیشتر آشنا شوید. وقتی TestRail یک defect ID واردشده را رندر میکند (مثلاً بهعنوان بخشی از test result)، بررسی میکند که defect plugin پیکربندیشده (اگر وجود داشته باشد) از جستجوی defectها پشتیبانی میکند یا نه (با بررسی گزینهٔ can_lookup که از متد get_meta برگردانده میشود).
اگر plugin از قابلیت lookup پشتیبانی کند، کاربران میتوانند نشانگر ماوس را روی defect ID نگه دارند تا وضعیت و توضیحات defect را ببینند. هر بار که کاربر این کار را انجام میدهد، TestRail از defect plugin میخواهد اطلاعات مربوط به defect را دریافت کند تا TestRail بتواند این دادهها را نمایش دهد. خوب است بدانید TestRail ممکن است در آینده از همین اطلاعات برای کارهای دیگری هم استفاده کند؛ مثلاً محاسبه defectهای باز و بسته در یک report.
درخواست اطلاعات درباره یک defect با متد lookup انجام میشود. قبل از فراخوانی این متد، TestRail همیشه متد configure را فراخوانی میکند تا plugin همه تنظیمات پیکربندی لازم را داشته باشد. متد lookup برای defect tracker فرضی ما، Bugs ، به این شکل است:
public function lookup($defect_id)
{
// Get the defect information via the Bugs API
$defect = $this->_bugs_get_defect($defect_id);
// Build the status_id based on the status property
if ($defect['status'] == 'Open')
{
$status_id = GI_DEFECTS_STATUS_OPEN;
}
elseif ($defect['status'] == 'Resolved')
{
$status_id = GI_DEFECTS_STATUS_RESOLVED;
}
else
{
$status_id = GI_DEFECTS_STATUS_CLOSED;
}
// Build the bug URL and project link
$bug_url = str::format('{0}?bug={1}',
$this->_address,
$defect['id']);
$project_link = str::format(
'{2}',
a($this->_address),
a($defect['project_id']),
h($defect['project']));
// Build the description
$description = str::format(
'{0}',
nl2br(
html::link_urls(
h($defect['description'])
)
)
);
// Return the defect details
return array(
'id' => $defect['id'],
'title' => $defect['title'],
'status_id' => $status_id,
'status' => $defect['status'],
'url' => $bug_url,
'description' => $description,
'attributes' => array(
'Type' => h($defect['type']),
'Status' => h($defect['status']),
'Project' => $project_link
)
);
}
این متد کمی طولانیتر از پیادهسازیهای دیگری است که تا اینجا دیدهایم؛ بنابراین بهتر است مراحل جداگانهای را که انجام میدهد بررسی کنیم. ابتدا جزئیات defect را با فراخوانی متد داخلی/خصوصی _bugs_get_defect دریافت میکنیم. این متد یا متدی مشابه، معمولاً API مربوط به defect tracker را فراخوانی میکند یا اطلاعات defect را در یک database جستجو میکند. اگر کد منبع این sample plugin را که در ادامه آمده دانلود کنید، میبینید که این متد همه جزئیات defect را بهصورت hard-coded نگه میدارد و در واقع هیچ فراخوانی web service انجام نمیدهد؛ اما برای نمایش سازوکار، همین کافی است.
بعد چند مقدار موردنیاز TestRail را آماده میکنیم، مثل status_id یا لینکها و description. مقدار status_id به TestRail میگوید defect باز است، resolve شده یا بسته شده است. اگر defect tracker بین resolved و closed تفاوتی قائل نیست (مثلاً bug یا باز است یا resolve شده)، حتماً وضعیت GI_DEFECTS_STATUS_CLOSED را مشخص کنید. TestRail ممکن است از status_id در آینده برای reportها و قابلیتهای دیگر استفاده کند.
بعضی از فیلدهایی که متد lookup برمیگرداند از HTML پشتیبانی میکنند. یعنی خیلی مهم است که قبل از برگرداندن stringها و valueها به TestRail، آنها را escape کنید؛ مگر اینکه دادهها را از defect tracker خودتان بهصورت HTML معتبر دریافت کرده باشید. اگر این کار را نکنید، خطر حمله cross-site scripting (XSS) وجود دارد و این یک ریسک امنیتی جدی است. برای escape کردن یک string، TestRail تابعهای h() و a() را برای escape کردن متنها و attributeهای tag، به همین ترتیب، ارائه میکند. برای مثال، attributeهای برگشتی میتوانند کد HTML داشته باشند (مثل لینکها)، و اگر valueهایی مثل نام project را escape نکنید، TestRail آنها را همانطور که هستند رندر میکند و مهاجم میتواند از طریق نام project کد JavaScript تزریق کند. همچنین توجه کنید که این متد توضیحات bug را داخل tag div قرار میدهد تا توضیحات با فونت monospace نمایش داده شود.
در پایان، این متد جزئیات defect را به TestRail برمیگرداند. علاوه بر مواردی مثل defect ID، عنوان، status و غیره، میتوانید attributes و description هم برگردانید. attributes میتوانند اطلاعاتی مثل project، issue type، component یا project area را شامل شوند. description هم مثل attributes از HTML پشتیبانی میکند و بنابراین میتوان از آن برای اضافه کردن انواع اطلاعات تکمیلی استفاده کرد. مطمئن شوید همه HTMLهای برگشتی tagها و formatting معتبر دارند، چون tagهای HTML خراب میتوانند layout و عملکرد TestRail را بههم بزنند. screenshot زیر نشان میدهد TestRail جزئیات defect برگشتی را چگونه رندر میکند (دقت کنید attributes بالای description و با پسزمینه آبی نمایش داده میشوند).

Push کردن defectها بدون dialog #
در ادامه، ارسال bug reportها از TestRail به یک ابزار defect tracking را بررسی میکنیم. ابتدا قابلیت push را بدون push dialog پیادهسازی میکنیم و در بخش بعدی سناریوی پیچیدهتر، یعنی استفاده از push dialog، را میبینیم. برای پیادهسازی push بدون push dialog، دو متد برای ما مهم هستند: prepare_push و push. TestRail متد prepare_push را فراخوانی میکند تا اطلاعات مربوط به dialog و فیلدهای قابل نمایش را بگیرد. اگر به push dialog نیازی نداریم و فقط میخواهیم bug report را بدون تعامل کاربر ارسال کنیم، کافی است اینجا false برگردانیم:
public function prepare_push($context)
{
return false;
}
برای اینکه واقعاً defect را push کنیم، باید متد push را هم پیادهسازی کنیم. برای ساختن یک defect report مفید، طبیعتاً به اطلاعاتی درباره test نیاز داریم (مثل عنوان test case یا comment واردشده)، و شاید جزئیات دیگری مثل کاربری که defect را push میکند. اینجاست که آرگومان $context که به همه متدهای مرتبط با push پاس داده میشود، به کار میآید. آرگومان $context شامل اطلاعات context مفیدی است؛ مثلاً جزئیات test case، test، کاربری که defect را push میکند و موارد دیگر. بیایید بخشی از اطلاعاتی را ببینیم که از طریق آرگومان $context پاس داده میشود:
Array
(
[event] => push
[tests] => Array
(
[0] => stdClass Object
(
[id] => 12
[run_id] => 1
[case_id] => 128
[status_id] => 1
[url] => http://testrail/index.php?/tests/view/12
[case] => stdClass Object
(
[id] => 128
Lorem ipsum dolor sit amet... #
=> Verify CSV import with enclosed test data files
[url] => http://testrail/index.php?/cases/view/128
)
[run] => stdClass Object
(
[id] => 1
[name] => File Formats
[config] =>
[plan_id] =>
[project_id] => 1
[url] => http://testrail/index.php?/runs/view/1
)
)
)
[test_count] => 1
[test_change] => stdClass Object
(
[status_id] => 1
[assignedto] =>
[comment] => Importing our standard Unicode CSV file (unitest1.csv) failed with the error message `Could not detect file encoding`.
[attachments] =>
[version] =>
[elapsed] =>
[defects] =>
)
[project] => stdClass Object
(
[id] => 1
[name] => Datahub
[url] => http://testrail/index.php?/projects/overview/1
)
[preferences] => Array
(
[type] => 1
[project] => DH
[component] => 10010
)
[user] => stdClass Object
(
[id] => 2
[name] => ..
[email] => test@example.com
)
)
همانطور که میبینیم، TestRail جزئیات testهای انتخابشده، test caseهای مرتبط، project، تغییر test (یعنی اطلاعاتی که کاربر در dialog Add Test Result وارد کرده) و موارد مشابه را فراهم میکند. همانطور که از ساختار داده مشخص است، TestRail میتواند چندین test را به defect plugin پاس بدهد. اگر کاربر چند test را انتخاب کرده باشد و از دکمه Add Test Result برای اضافه کردن یک result به همه آن testها بهصورت همزمان استفاده کرده باشد (دکمه mass action)، TestRail چند رکورد test را به script پاس میدهد. push کردن defect و برگرداندن defect ID جدید میتواند به این شکل باشد:
public function push($context, $input)
{
// Build the summary/title
$test = current($context['tests']);
$summary = 'Failed test: ' . $test->case->title;
if ($context['test_count'] > 1)
{
$summary .= ' (+others)';
}
// Build the comment (based on the test result comment
// and links/URLs of the tests
if ($context['test_change']->comment)
{
$comment = $context['test_change']->comment;
$comment .= "\n";
}
else
{
$comment = '';
}
$tests = $context['tests'];
foreach ($tests as $test)
{
$comment .= "\nTest: ";
$comment .= $test->case->title;
$comment .= "\n";
$comment .= $test->url;
}
// We hard code a few other details here for demonstration
// purposes. We could also select these attributes based
// on context information such as the test suite or user
$project = $context['project']->name;
$type = 'Bug';
$component = '(default)';
// Push the defect and return the new defect ID
$defect_id = $this->_bugs_push_defect(
$summary,
$comment,
$project,
$type,
$component
);
return $defect_id;
}
متد push متد، عنوان/خلاصه و comment گزارش باگ را بر اساس test result واردشده و اطلاعات context میسازد. سپس متد داخلی _bugs_push_defect را صدا میزند تا گزارش باگ واقعی ثبت شود. این متد باید فراخوانی واقعی یک web service API یا نوشتن گزارش باگ در database را انجام دهد. کافی است defect ID جدید را به TestRail برگردانیم تا TestRail این ID را به فیلد Defects برای ما اضافه کند.
ارسال defectها با dialog #
حالا که ساخت defect pluginی را دیدیم که میتواند گزارشهای باگ را بدون دخالت کاربر ارسال کند، plugin را بهروزرسانی میکنیم تا از Push Defect dialog استفاده کند. با این dialog، testerها هنگام ارسال defectها به defect tracker میتوانند توضیحات باگ را تغییر دهند یا project دیگری انتخاب کنند. اولین تغییری که باید بدهیم، بهروزرسانی prepare_push متد است. بهجای برگرداندن false برای نشان دادن اینکه به dialog نیاز نداریم، میتوانیم form schemaای مثل این برگردانیم:
public function prepare_push($context)
{
// Return a form with the following fields/properties
return array(
'fields' => array(
'summary' => array(
'type' => 'string',
'label' => 'Summary',
'required' => true,
'size' => 'full'
),
'type' => array(
'type' => 'dropdown',
'label' => 'Issue Type',
'required' => true,
'remember' => true,
'size' => 'compact'
),
'project' => array(
'type' => 'dropdown',
'label' => 'Project',
'required' => true,
'remember' => true,
'cascading' => true,
'size' => 'compact'
),
'component' => array(
'type' => 'dropdown',
'label' => 'Component',
'required' => true,
'remember' => true,
'depends_on' => 'project',
'size' => 'compact'
),
'description' => array(
'type' => 'text',
'label' => 'Description'
)
)
);
}
form schema به TestRail میگوید به کدام form fieldها نیاز داریم. defect script لازم نیست خودش dialog را render کند، چون TestRail بر اساس form schemaای که در prepare_push متد برمیگردانیم، push dialog را بهصورت خودکار برای ما render میکند. بیشتر بخشهای form schema در مثال بالا واضحاند. ما فهرستی از form fieldهایی را برمیگردانیم که TestRail باید نمایش دهد.
کلید آرایهی هر field، مثلا description، نامی است که TestRail برای پاس دادن دادههای ورودی به script ما استفاده میکند. گزینهی type هر field در حال حاضر میتواند یکی از text ، dropdown یا string باشد و به TestRail میگوید به چه نوع fieldی نیاز داریم. مقدار string یک input متنی تکخطی است، در حالی که text میتواند چند خط ورودی بگیرد. گزینهی required مشخص میکند که کاربر حتما باید این field را پر کند یا پر کردن آن اختیاری است، و گزینهی label نام field را در dialog مشخص میکند.
گزینهی size عرض field را مشخص میکند؛ اگر مقدار آن full باشد، field کل عرض افقی dialog را پر میکند. اگر compact را بهعنوان اندازهی field مشخص کنید، TestRail تلاش میکند چند field فشرده را در یک خط نمایش دهد. این فقط برای compact fieldهایی صدق میکند که با هم در form schema تعریف شدهاند. اگر گزینهی remember را مشخص کنید، TestRail آخرین مقدار واردشده برای آن field را در project فعلی TestRail ذخیره میکند. این کار نگهداشتن مقدارهای قبلی فرم، مثل project area یا sub component، را ساده میکند تا کاربر مجبور نباشد همان دادهها را بارها وارد کند. کمی جلوتر در همین بخش میبینیم این قابلیت چطور کار میکند.
برخی fieldها ممکن است به fieldهای دیگر وابسته باشند. مثلا اگر یک Project dropdown field داشته باشید، مقدارهای field مرتبطِ Project Area به project انتخابشده وابسته است. TestRail برای این حالت از field dependency پشتیبانی میکند. اگر کاربر project دیگری انتخاب کند، TestRail از defect script میخواهد project areaهای معتبر برای project تازه انتخابشده را برگرداند و مقدار field Project Area را پاک میکند. field dependencyها با گزینهی depends_on مشخص میشوند و در حال حاضر فقط برای dropdown fieldها پشتیبانی میشوند. همچنین لازم است fieldهایی را که سایر fieldها میتوانند به آنها وابسته باشند، بهعنوان cascade (از طریق گزینه مربوطه).
حالا که schema فرم را مشخص کردهایم، باید مقدارهای معتبر dropdown و متنهای پیشفرض فیلدهای dialog را هم به TestRail بدهیم. این کار از طریق prepare_field انجام میشود. هر بار که TestRail dialog را initialize میکند، یا وقتی یکی از فیلدهای cascade تغییر میکند، TestRail از defect plugin میخواهد اطلاعات فیلدهای مرتبط را ارائه کند. TestRail متد prepare_field را برای هر فیلدی که به اطلاعات آن نیاز دارد فراخوانی میکند.
public function prepare_field($context, $input, $field)
{
$data = array();
// Take the preferences of the user into account, but only
// for the initial form rendering (not for cascading loads).
if ($context['event'] == 'prepare')
{
$prefs = arr::get($context, 'preferences');
}
else
{
$prefs = null;
}
// And then build the options and default values for the
// form fields and return them.
switch ($field)
{
case 'summary':
$data['default'] =
$this->_get_summary_default($context);
break;
case 'description':
$data['default'] =
$this->_get_description_default($context);
break;
case 'type':
$data['options'] = $this->_bugs_get_types();
// Select the stored preference or the first item in
// the list otherwise.
$default = arr::get($prefs, 'type');
if ($default)
{
$data['default'] = $default;
}
else
{
if ($data['options'])
{
$data['default'] = key($data['options']);
}
}
break;
case 'project':
$data['default'] = arr::get($prefs, 'project');
$data['options'] = $this->_bugs_get_projects();
break;
case 'component':
if (isset($input['project']))
{
$data['default'] = arr::get($prefs, 'component');
$data['options'] = $this->_bugs_get_components(
$input['project']);
}
break;
}
return $data;
}
TestRail سه آرگومان را به prepare_field ما میدهد: $context آرگومان اول شامل اطلاعات context است که از متدهای قبلی با آن آشنا هستیم. آرگومان $input شامل دادههای واقعیای است که کاربر در push dialog وارد کرده است؛ این مورد مخصوصا برای فراخوانیهای dropdownهای cascade مفید است. آرگومان $field نام فیلدی را در خود دارد که متد برای آن فراخوانی شده است، چون این متد برای هر فیلد بهصورت جداگانه اجرا میشود.
TestRail همچنین preferences کاربر فعلی را برای project فعلی بهعنوان بخشی از آرگومان $context ارسال میکند. بنابراین اولین کاری که متد prepare_field انجام میدهد این است که اگر TestRail در حال initialize کردن dialog باشد، preferences کاربر را در یک متغیر محلی کپی میکند. اگر این فراخوانی بعدی برای یک فیلد dropdown از نوع cascade باشد، preferences را نادیده میگیریم.
بعد از آن، داده مناسب همان فیلد را به TestRail برمیگردانیم. این کار را در یک switch statement بزرگ انجام میدهیم که بسته به فیلدی که TestRail برای آن داده میخواهد، کد مربوطه را اجرا میکند.
برای مثال، وقتی TestRail مقدارهای ممکن را برای فیلد Project درخواست میکند، کد زیر اجرا میشود:
case 'project':
$data['default'] = arr::get($prefs, 'project');
$data['options'] = $this->_bugs_get_projects();
break;
TestRail برای یک فیلد dropdown اساسا به دو مورد نیاز دارد: گزینههایی که کاربر میتواند انتخاب کند و گزینه پیشفرضی که انتخاب شده است. برای فیلدهای text و string فقط مقدار default باید مشخص شود، چون فیلد text یا string گزینهای برای انتخاب ندارد. در مثال ما، گزینه پیشفرض بر اساس preference کاربر انتخاب میشود. بنابراین اگر کاربر قبلا project خاصی را انتخاب کرده باشد، همان project را برمیگردانیم تا لازم نباشد دوباره آن را مشخص کند. به همین شکل، متنهای پیشفرض summary/title و فیلد description را بر اساس جزئیات test تولید میکنیم. در نتیجه dialog ما چیزی شبیه تصویر زیر خواهد بود.

در مثال ما، متدهایی مانند _bugs_get_projects را در عمل بهطور کامل پیادهسازی نمیکنیم. در یک plugin کامل، این متد با استفاده از web service API مربوط به defect tracker فهرست projectها را دریافت میکند، یا آن را از database میخواند. در اینجا فقط یک فهرست hard-coded از projectها را برمیگردانیم. اگر projectهای شما مرتب تغییر نمیکنند، این روش هم میتواند پیادهسازی قابل قبولی باشد:
private function _bugs_get_projects()
{
return array(
'dh' => 'Datahub',
'pr' => 'Presenter',
'wr' => 'Writer'
);
}
دقت کنید که اینجا از IDها بهعنوان کلیدهای array استفاده میکنیم. وقتی کاربر روی دکمه submit کلیک کند، TestRail همین IDها را بهعنوان مقدار ورودی به متد push ما میفرستد. اما قبل از پیادهسازی متد push، بیایید کوتاه نگاهی به متد validate_push بیندازیم. این متد به ما اجازه میدهد قبل از پذیرش مقدارهای واردشده برای bug report، ورودی کاربر را validate کنیم. اگر به validation بیشتری روی دادهها نیاز ندارید، پیادهسازی این متد ضروری نیست؛ اما برای اعمال formatها یا محدودیتهای خاص روی ورودی، مثل date، میتواند مفید باشد. مثال زیر از متد validate_push برای محدود کردن تعداد کاراکترهای فیلد summary به ۱۰۰ کاراکتر استفاده میکند:
public function validate_push($context, $input)
{
if (isset($input['summary']))
{
if (str::len($input['summary']) > 100)
{
throw new ValidationException( 'Field Summary cannot exceed 100 characters.');
}
}
}
بعد از اینکه کاربر bug report را وارد کرد، روی دکمه submit کلیک کرد و script ورودی را از طریق متد validate_push validate کرد، TestRail متد push را برای ارسال bug report فراخوانی میکند. مشابه مثال بدون dialog که بالاتر دیدیم، متد push گزارش را ارسال میکند. دقت کنید که این بار بهجای ساختن bug report از آرگومان $input از آرگومان $context استفاده میکنیم:
public function push($context, $input)
{
// Push the defect and return the new defect ID
$defect_id = $this->_bugs_push_defect(
$input['summary'],
$input['description'],
$input['project'],
$input['type'],
$input['component']
);
return $defect_id;
}
تمام شد! حالا یک defect plugin کامل پیادهسازی کردهایم که از قابلیتهای look up و push پشتیبانی میکند، administrator میتواند آن را از داخل TestRail پیکربندی کند، و برای فهرست projectها از dropdown نوع cascade پشتیبانی دارد. میتوانید sample script کامل را از بخش زیر دانلود کنید و نمونه scriptهای بیشتری را هم ببینید.
دانلود #
میتوانید sample script کامل مطرحشده در این مقاله را از اینجا دانلود کنید:
نمونه Bugs.php #
فایل PHP شامل sample script کامل
برای دیدن نمونههای بیشتر از defect pluginهای واقعی، بهتر است defect pluginهایی را بررسی کنید که همراه TestRail ارائه میشوند. میتوانید defect pluginها را در installation directory مربوط به TestRail و در مسیر زیر پیدا کنید: app/plugins/defects اگر درباره ساخت یا سفارشیسازی defect pluginها سؤال دیگری دارید، لطفا با ما تماس بگیرید.

