С 1.22.00.
Эта страница документации не завершена.
Старт
Для работы API тестов нужно заполнить 2 конфигурационные переменные:
$conf{API_TEST_USER_LOGIN}
— логин пользователя для тестов$conf{API_TEST_USER_PASSWORD}
— пароль пользователя для тестов
Опционально можете заполнить $conf{API_TEST_URL}
- URL для тестов. По умолчанию это значение localhost.
Модуль
За пример взят модуль Portal.
Расположение Abills/modules/Portal
Создаём:
- папку t
- папку t/schemas
- папку t/schemas/admin
- папку t/schemas/user
- файл t/Api.t
Создаём папки для каждого эндпоинта, в ADMIN или(и) USER API например:
- articles_list - GET /portal/articles
- articles_info - GET /portal/articles/:id/
- article_add - POST /portal/articles
- articles_update - PUT /portal/articles/:id/
- article_delete - DELETE /portal/articles/:id/
Чётких правил по названию папки нет, но рекомендуем использовать конструкцию subpath_action
Ядро
За пример взят микромодуль Companies.
Расположение - t/Api
Создаём:
- папку Companies
- папку Companies/schemas
- папку Companies/schemas/admin
- файл Companies/Api.t
Создаём папки для каждого эндпоинта, в ADMIN или(и) USER API например:
- companies - GET /companies
- company - GET /companies/:id/
- company_add - POST /companies
- companies_change - PUT /companies/:id/
- company_delete - DELETE /companies/:id/
Чётких правил по названию папки нет, но рекомендуем использовать конструкцию subpath_action
Написание Api.t
На данный момент этот раздел документации не завершён.
Спецификация Api.t ещё полностью не определена.
Следите за обновлениями.
=head1 NAME
Portal API test
=cut
use strict;
use warnings;
use lib '../';
use Test::More;
use FindBin '$Bin';
use FindBin qw($RealBin);
use JSON;
# Подключаем конфиг
require $Bin . '/../../../../libexec/config.pl';
# Добавляем пути компилятора
BEGIN {
our $libpath = '../../../../';
my $sql_type = 'mysql';
unshift(@INC, $libpath . "Abills/$sql_type/");
unshift(@INC, $libpath);
unshift(@INC, $libpath . 'lib/');
unshift(@INC, $libpath . 'libexec/');
unshift(@INC, $libpath . 'Abills/');
unshift(@INC, $libpath . 'Abills/modules/');
}
use Abills::Defs;
use Abills::Api::Tests::Init qw(test_runner folder_list help);
use Abills::Base qw(parse_arguments);
use Admins;
use Users;
use Portal;
our (
%conf
);
# Обязательно подключение к базе
my $db = Abills::SQL->connect(
$conf{dbtype}, $conf{dbhost}, $conf{dbname}, $conf{dbuser}, $conf{dbpasswd},
{
CHARSET => ($conf{dbcharset}) ? $conf{dbcharset} : undef,
dbdebug => $conf{dbdebug}
}
);
my $admin = Admins->new($db, \%conf);
my $Users = Users->new($db, $admin, \%conf);
my $Portal = Portal->new($db, $admin, \%conf);
# Выбираем последнего пользователя к нашим кредам
my $user = $Users->list({
LOGIN => $conf{API_TEST_USER_LOGIN} || 'test',
COLS_NAME => 1,
COLS_UPPER => 1
})->[0];
# Выбираем с базы articles
my $articles = $Portal->portal_articles_list({
COLS_NAME => 1
});
# Выбираем с базы menus
my $menus = $Portal->portal_menu_list({
ID => '_SHOW',
COLS_NAME => 1
});
# Выбираем с базы newsletters
my $newsletters = $Portal->portal_newsletter_list({
COLS_NAME => 1
});
# Выбираем с базы attachments
my $attachments = $Portal->attachment_list({
ID => '_SHOW',
COLS_NAME => 1
});
# Парсим аргументы с stdin
my $ARGS = parse_arguments(\@ARGV);
# ADMIN API key
my $apiKey = $ARGS->{KEY} || $ARGV[$#ARGV] || q{};
# Получаем список request, schema.json
my @test_list = folder_list($ARGS, $RealBin);
my $debug = $ARGS->{DEBUG} || 0;
# Определяем ли это help, и принтим его в случае
if (($ARGV[0] && lc($ARGV[0]) eq 'help') || defined($ARGS->{help}) || defined($ARGS->{HELP})) {
help();
exit 0;
}
# Берём динамические айдишки для мока.
# Тоесть, база перед этим должна быть заполненная данными.
my $article_id = $articles->[-1]->{id} || 0;
my $newsletter_id = $newsletters->[-1]->{id} || 0;
my $attachment_id = $attachments->[-1]->{id} || 0;
my $menu_id = $menus->[-1]->{id} || 0;
# Проходимся по списку, и заменяем path params на реальные данные.
foreach my $test (@test_list) {
if ($test->{path} =~ /portal\/articles\/:id/g) {
$test->{path} =~ s/:id/$article_id/g;
}
elsif ($test->{path} =~ /portal\/newsletter\/:id/g) {
$test->{path} =~ s/:id/$newsletter_id/g;
}
elsif ($test->{path} =~ /portal\/menus\/:id/g) {
$test->{path} =~ s/:id/$menu_id/g;
}
elsif ($test->{path} =~ /portal\/attachment\/:id/g) {
$test->{path} =~ s/:id/$attachment_id/g;
}
elsif ($test->{path} =~ /user\/portal\/news\/:id/g) {
$test->{path} =~ s/:id/$article_id/
}
}
# Обязательно: включаем тесты по списку
test_runner({
apiKey => $apiKey,
debug => $debug,
args => $ARGS
}, \@test_list);
# Завершаем тест с накопленными результатами
done_testing();
1;
Создание реквеста и json-schema
И в каждом эндпоинте создаём файлы:
- request.json - JSON интерпретация заданного реквеста
- schema.json - JSON-SCHEMA ожидаемого ответа
Про json-schema почитать тут.
Create
{
"body": {
"addressFlat": "4",
"archive": 1,
"buildId": 8,
"content": "<p>Новая Open Source версия биллинга!</p>\n\n\n\n<p>Полный список новинок, исправлений и улучшений биллинга к новому релизу!</p>",
"date": "2023-01-27",
"districtId": 8,
"domainId": 0,
"endDate": "",
"gid": 0,
"importance": 0,
"name": "Releases",
"onMainPage": 0,
"permalink": "releases-abills-095-blackout",
"picture": "https://demo.abills.net.ua:9443/images/attach/portal/13863233.jpg",
"portalMenuId": 8,
"shortDescription": "Встречайте новый релиз 2023",
"stName": "",
"status": 1,
"streetId": 0,
"tagName": "",
"tags": 0,
"title": "Релиз ABillS 0.95 Blackout"
},
"method": "POST",
"name": "ADMIN_PORTAL_ARTICLES_ADD",
"path": "portal/articles/"
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"affected": {
"type": "integer"
},
"insertId": {
"type": "integer"
},
"total": {
"type": "integer"
}
},
"required": ["affected", "insertId", "total"]
}
Read
{
"method": "GET",
"name": "ADMIN_PORTAL_ARTICLES_LIST",
"path": "portal/articles/"
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"archive": {
"type": "integer"
},
"addressFlat": {
"type": "string"
},
"buildId": {
"type": "number"
},
"content": {
"type": "string"
},
"date": {
"type": "string"
},
"deeplink": {
"type": "integer"
},
"districtId": {
"type": "string"
},
"domainId": {
"type": "integer"
},
"endDate": {
"type": "string"
},
"etimestamp": {
"type": "integer"
},
"gid": {
"type": "integer"
},
"importance": {
"type": "integer"
},
"name": {
"type": "string"
},
"onMainPage": {
"type": "integer"
},
"permalink": {
"type": "string"
},
"picture": {
"type": "string"
},
"portalMenuId": {
"type": "integer"
},
"shortDescription": {
"type": "string"
},
"stName": {
"type": "string"
},
"status": {
"type": "integer"
},
"streetId": {
"type": "integer"
},
"tagName": {
"type": "string"
},
"tags": {
"type": "integer"
},
"title": {
"type": "string"
},
"url": {
"type": "string"
},
"utimestamp": {
"type": "integer"
}
},
"required": [
"id",
"archive",
"addressFlat",
"buildId",
"content",
"date",
"deeplink",
"districtId",
"domainId",
"endDate",
"etimestamp",
"gid",
"importance",
"name",
"onMainPage",
"permalink",
"picture",
"portalMenuId",
"shortDescription",
"stName",
"status",
"streetId",
"tagName",
"tags",
"title",
"url",
"utimestamp"
]
}
},
"total": {
"type": "number"
}
},
"required": [
"list",
"total"
]
}
Update
{
"body": {
"addressFlat": "4",
"archive": 1,
"buildId": 8,
"content": "<p>Новая Open Source версия биллинга!</p>\n\n\n\n<p>Полный список новинок, исправлений и улучшений биллинга к новому релизу!</p>",
"date": "2023-01-27",
"districtId": 8,
"domainId": 0,
"endDate": "",
"gid": 0,
"importance": 0,
"name": "Releases",
"onMainPage": 0,
"permalink": "releases-abills-095-blackout",
"picture": "https://demo.abills.net.ua:9443/images/attach/portal/13863233.jpg",
"portalMenuId": 8,
"shortDescription": "Встречайте новый релиз 2023",
"stName": "",
"status": 1,
"streetId": 0,
"tagName": "",
"tags": 0,
"title": "Релиз ABillS 0.95 Blackout"
},
"method": "PUT",
"name": "ADMIN_PORTAL_ARTICLE_UPDATE",
"path": "portal/articles/:id/"
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"affected": {
"type": "integer"
},
"total": {
"type": "integer"
}
},
"required": ["affected", "total"]
}
Delete
{
"method": "DELETE",
"name": "ADMIN_PORTAL_ARTICLE_DELETE",
"path": "portal/articles/:id/"
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"result": {
"type": "string"
}
},
"required": [
"result"
]
}
Запуск теста
Для запуска теста на USER API - запускайте созданный вами Api.t, будет взяты данные автоматически с конфига.
Для запуска теста на ADMIN API - запускайте с параметром KEY=*ваш API_KEY*
Практики
- Чтобы не писать request.json руками - используйте ChatGPT.
Отправляйте ему OpenAPI вашего пути, и он сгенерирует нужный вам schema.json.
Это сэкономит вам время, и позволит избежать человеческого фактора ошибки.