Testing de modulos PrestaShop — PHPUnit y Behat
Actualizado: 2024-12-01
Los modulos de PrestaShop pueden testearse con PHPUnit para logica de negocio aislada y Behat para flujos de integracion. El principal reto es aislar el modulo de las clases globales de PrestaShop (Context, Configuration, Db).
#Estructura de tests recomendada
Estructura de directorios para tests
text
mymodule/
├── src/
│ └── Service/
│ └── PriceCalculator.php
├── tests/
│ ├── Unit/
│ │ └── Service/
│ │ └── PriceCalculatorTest.php
│ ├── Integration/
│ │ └── Repository/
│ │ └── ItemRepositoryTest.php
│ └── bootstrap.php ← carga el autoloader
├── composer.json
└── phpunit.xml
#PHPUnit — unit tests
tests/Unit/Service/PriceCalculatorTest.php
php
<?php
declare(strict_types=1);
namespace MyModule\Tests\Unit\Service;
use MyModule\Service\PriceCalculator;
use PHPUnit\Framework\TestCase;
class PriceCalculatorTest extends TestCase
{
private PriceCalculator $calculator;
protected function setUp(): void
{
$this->calculator = new PriceCalculator(0.21); // IVA 21%
}
public function testCalculatePriceWithTax(): void
{
$result = $this->calculator->withTax(100.0);
$this->assertEqualsWithDelta(121.0, $result, 0.001);
}
public function testCalculatePriceWithDiscount(): void
{
$result = $this->calculator->withDiscount(100.0, 10); // 10% dto
$this->assertEqualsWithDelta(90.0, $result, 0.001);
}
/** @dataProvider priceProvider */
public function testCalculateVariousPrices(float $base, float $tax, float $expected): void
{
$calc = new PriceCalculator($tax);
$result = $calc->withTax($base);
$this->assertEqualsWithDelta($expected, $result, 0.001);
}
public static function priceProvider(): array
{
return [
'IVA 21%' => [100.0, 0.21, 121.0],
'IVA 10%' => [50.0, 0.10, 55.0],
'Sin IVA' => [75.0, 0.00, 75.0],
];
}
}
#Mockear el Context de PrestaShop
Mockear Context, Configuration y Db en unit tests
php
<?php
declare(strict_types=1);
namespace MyModule\Tests\Unit;
use PHPUnit\Framework\TestCase;
class ModuleWithContextTest extends TestCase
{
protected function setUp(): void
{
// ── Mockear Configuration ──
// Requiere un stub o una clase fake si Configuration no tiene interface
// Opcion 1: usar la clase real con una BD de test
// Opcion 2: inyectar Configuration como dependencia y mockearla
// ── Mockear Context ──
$context = $this->createMock(\Context::class);
$context->language = $this->createMock(\Language::class);
$context->language->id = 1;
$context->currency = $this->createMock(\Currency::class);
$context->currency->iso_code = 'EUR';
$context->shop = $this->createMock(\Shop::class);
$context->shop->id = 1;
// Asignar el mock al singleton
\Context::setInstanceForTesting($context); // solo disponible en PS 8.1+
}
// ── Alternativa para PS < 8.1: heredar de un TestCase base del core ──
// use PrestaShop\PrestaShop\Tests\Unit\Core\UnitTestCase;
}
#Testear servicios Symfony
Test de un servicio con dependencias inyectadas
php
<?php
declare(strict_types=1);
namespace MyModule\Tests\Unit\Service;
use Doctrine\ORM\EntityManagerInterface;
use MyModule\Entity\MyItem;
use MyModule\Repository\MyItemRepository;
use MyModule\Service\ItemService;
use PHPUnit\Framework\TestCase;
class ItemServiceTest extends TestCase
{
public function testFindActiveItems(): void
{
// Crear mocks de las dependencias
$repository = $this->createMock(MyItemRepository::class);
$em = $this->createMock(EntityManagerInterface::class);
// Configurar comportamiento del mock
$item1 = new MyItem();
$repository->expects($this->once())
->method('findBy')
->with(['active' => true])
->willReturn([$item1]);
$em->expects($this->once())
->method('getRepository')
->with(MyItem::class)
->willReturn($repository);
// Testear el servicio
$service = new ItemService($em);
$result = $service->getActiveItems();
$this->assertCount(1, $result);
$this->assertSame($item1, $result[0]);
}
}
#composer.json y phpunit.xml
composer.json — configuracion de testing
json
{
"name": "myvendor/mymodule",
"type": "prestashop-module",
"require": {
"php": ">=7.4"
},
"require-dev": {
"phpunit/phpunit": "^9.5 || ^10.0",
"phpstan/phpstan": "^1.0"
},
"autoload": {
"psr-4": {
"MyModule\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"MyModule\\Tests\\": "tests/"
}
},
"scripts": {
"test": "vendor/bin/phpunit",
"phpstan": "vendor/bin/phpstan analyse src --level=5"
}
}
phpunit.xml — configuracion de 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"
colors="true">
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Integration">
<directory>tests/Integration</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
</phpunit>
Descargar en Markdown
Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.