Налаштування PHPUnit-тестів для модулів 1С-Бітрікс

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Налаштування PHPUnit-тестів для модулів 1С-Бітрікс
Проста
~1 робочий день
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Налаштування PHPUnit-тестів для модулів 1С-Бітрікс

Модуль 1С-Бітрікс без тестів — чорна скринька. Виправили одне — зламали інше. Особливо болюче це в модулях з бізнес-логікою: розрахунок знижок, інтеграції із зовнішніми API, обробка замовлень. PHPUnit для модулів Бітрікс має свою специфіку: ядро Бітрікс потрібно завантажувати (і це повільно), статичні виклики заважають ізоляції, а сам Бітрікс надає власні інструменти тестування для ORM.

Налаштування PHPUnit-тестів для модулів 1С-Бітрікс

Структура тестів у модулі Бітрікс

/local/modules/vendor.mymodule/
    lib/
        Services/
            DiscountService.php
            ShippingCalculator.php
        Repository/
            OrderRepository.php
    tests/
        bootstrap.php
        Unit/
            Services/
                DiscountServiceTest.php
                ShippingCalculatorTest.php
        Integration/
            Repository/
                OrderRepositoryTest.php
    phpunit.xml
    composer.json

phpunit.xml для модуля Бітрікс

<?xml version="1.0" encoding="UTF-8"?>
<phpunit
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
    bootstrap="tests/bootstrap.php"
    cacheDirectory=".phpunit.cache"
    executionOrder="depends,defects"
    requireCoverageMetadata="false"
    beStrictAboutCoverageMetadata="false"
>
    <testsuites>
        <testsuite name="Unit">
            <directory>tests/Unit</directory>
        </testsuite>
        <testsuite name="Integration">
            <directory>tests/Integration</directory>
        </testsuite>
    </testsuites>

    <source>
        <include>
            <directory suffix=".php">lib</directory>
        </include>
    </source>

    <coverage>
        <report>
            <html outputDirectory="tests/_coverage"/>
            <clover outputFile="tests/_coverage/clover.xml"/>
        </report>
    </coverage>
</phpunit>

bootstrap.php: два режими

<?php
// tests/bootstrap.php

$bitrixLoaded = false;

// Unit-тести без ядра Бітрікс — швидко
if (getenv('PHPUNIT_NO_BITRIX') === 'true') {
    require_once __DIR__ . '/../vendor/autoload.php';
    return;
}

// Integration-тести з ядром Бітрікс — повільніше
define('NO_KEEP_STATISTIC', true);
define('NOT_CHECK_PERMISSIONS', true);
define('BX_WITH_ON_AFTER_EPILOG', false);
define('BX_NO_ACCELERATOR_RESET', true);
define('STOP_STATISTICS', true);

$docRoot = realpath(__DIR__ . '/../../../..');
$_SERVER['DOCUMENT_ROOT'] = $docRoot;
$_SERVER['HTTP_HOST']     = 'localhost';
$_SERVER['SERVER_NAME']   = 'localhost';

require_once $docRoot . '/bitrix/modules/main/include/prolog_before.php';
require_once __DIR__ . '/../vendor/autoload.php';

\Bitrix\Main\Loader::includeModule('vendor.mymodule');

Unit-тест з ізольованою бізнес-логікою

// tests/Unit/Services/DiscountServiceTest.php
namespace Tests\Unit\Services;

use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
use Vendor\Mymodule\Services\DiscountService;
use Vendor\Mymodule\Repository\OrderRepositoryInterface;
use Vendor\Mymodule\Repository\UserRepositoryInterface;

class DiscountServiceTest extends TestCase
{
    private DiscountService $service;
    private OrderRepositoryInterface&MockObject $orders;
    private UserRepositoryInterface&MockObject $users;

    protected function setUp(): void
    {
        $this->orders  = $this->createMock(OrderRepositoryInterface::class);
        $this->users   = $this->createMock(UserRepositoryInterface::class);
        $this->service = new DiscountService($this->orders, $this->users);
    }

    public function testNewUserGetsNoDiscount(): void
    {
        $this->orders->method('countCompletedByUser')->willReturn(0);
        $this->users->method('getRegistrationDays')->willReturn(5);

        $discount = $this->service->calculate(userId: 1, orderAmount: 5000.0);

        $this->assertSame(0.0, $discount);
    }

    public function testUserWith5OrdersGets5PercentDiscount(): void
    {
        $this->orders->method('countCompletedByUser')->willReturn(5);
        $this->users->method('getRegistrationDays')->willReturn(180);

        $discount = $this->service->calculate(userId: 1, orderAmount: 5000.0);

        $this->assertSame(250.0, $discount); // 5% від 5000
    }

    public function testDiscountCappedAt20Percent(): void
    {
        $this->orders->method('countCompletedByUser')->willReturn(100);
        $this->users->method('getRegistrationDays')->willReturn(1000);

        $discount = $this->service->calculate(userId: 1, orderAmount: 10000.0);

        $this->assertSame(2000.0, $discount); // 20% — максимум
    }
}

Integration-тест з ORM Бітрікс

// tests/Integration/Repository/OrderRepositoryTest.php
namespace Tests\Integration\Repository;

use PHPUnit\Framework\TestCase;
use Vendor\Mymodule\Repository\OrderRepository;

class OrderRepositoryTest extends TestCase
{
    private static int $testUserId;

    public static function setUpBeforeClass(): void
    {
        // Створюємо тестового користувача
        $user = new \CUser();
        self::$testUserId = $user->Add([
            'LOGIN'      => 'test_' . uniqid(),
            'PASSWORD'   => 'Test123!',
            'EMAIL'      => 'test_' . uniqid() . '@test.ru',
            'ACTIVE'     => 'Y',
            'GROUP_ID'   => [2],
        ]);
    }

    public static function tearDownAfterClass(): void
    {
        // Видаляємо тестові дані
        \CUser::Delete(self::$testUserId);
    }

    public function testCountCompletedOrdersReturnsCorrectNumber(): void
    {
        $repo = new OrderRepository();

        // Створюємо тестові замовлення через Sale API
        $this->createTestOrder(self::$testUserId, 'F'); // завершене
        $this->createTestOrder(self::$testUserId, 'F');
        $this->createTestOrder(self::$testUserId, 'N'); // нове, не рахуємо

        $count = $repo->countCompletedByUser(self::$testUserId);
        $this->assertSame(2, $count);
    }

    private function createTestOrder(int $userId, string $status): void
    {
        \Bitrix\Main\Loader::includeModule('sale');

        $order = \Bitrix\Sale\Order::create('s1', $userId);
        $order->setField('STATUS_ID', $status);
        $order->setField('CURRENCY', 'RUB');
        $order->setField('PRICE', 1000.0);
        $order->save();
    }
}

Запуск тільки unit-тестів (без завантаження Бітрікс)

# Швидкі unit-тести без ядра Бітрікс (секунди)
PHPUNIT_NO_BITRIX=true vendor/bin/phpunit --testsuite Unit

# Інтеграційні тести з ядром (хвилини)
vendor/bin/phpunit --testsuite Integration

# Всі тести з покриттям (потребує Xdebug або PCOV)
XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-html tests/_coverage

CI/CD конфігурація

# .github/workflows/tests.yml
- name: Run PHPUnit Unit tests
  run: |
    cd local/modules/vendor.mymodule
    PHPUNIT_NO_BITRIX=true vendor/bin/phpunit --testsuite Unit
  env:
    PHPUNIT_NO_BITRIX: 'true'

Терміни

Завдання Терміни
Налаштування PHPUnit, bootstrap, конфігурація для модуля 4–8 годин
Unit-тести для бізнес-логіки модуля (до 10 класів) 1–2 дні
Integration-тести з ORM Бітрікс 1–2 дні
Рефакторинг модуля для тестованості + покриття 70%+ 3–7 днів