From 8dbbcd2f5634258fe122d99dc61085f48cb8fff7 Mon Sep 17 00:00:00 2001 From: David Lambauer Date: Sun, 19 Apr 2026 19:07:13 +0200 Subject: [PATCH] ci: add unit test workflow and minimal test bootstrap Extract CI infrastructure from #49 so tests run on main before any feature PR merges. Feature-specific tests remain with their respective PRs. - GitHub Actions workflow running PHP 8.2/8.3/8.4 via mage-os/github-actions - PHPUnit bootstrap using Magento's FactoryGenerator/ProxyGenerator - phpunit.xml.dist test runner config - ProductMockTrait for shared product mocking - RequestTest as a smoke test covering the existing Request DTO - composer.json: add magento/* framework deps required by the bootstrap (also resolves #22, supersedes #39) --- .github/workflows/unit-tests.yml | 28 ++++++++++ Test/Unit/Model/Product/RequestTest.php | 33 ++++++++++++ Test/Unit/Trait/ProductMockTrait.php | 71 +++++++++++++++++++++++++ Test/Unit/bootstrap.php | 24 +++++++++ composer.json | 13 ++++- phpunit.xml.dist | 16 ++++++ 6 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/unit-tests.yml create mode 100644 Test/Unit/Model/Product/RequestTest.php create mode 100644 Test/Unit/Trait/ProductMockTrait.php create mode 100644 Test/Unit/bootstrap.php create mode 100644 phpunit.xml.dist diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..8b47347 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,28 @@ +run-name: ${{ github.actor }} is running Unit Tests +on: + push: + branches: + - main + - feature/* + pull_request: + branches: + - main + +permissions: + contents: write + +jobs: + unit-test: + strategy: + matrix: + php_version: + - 8.2 + - 8.3 + - 8.4 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: mage-os/github-actions/unit-test@main + with: + php_version: ${{ matrix.php_version }} + composer_auth: ${{ secrets.COMPOSER_AUTH }} diff --git a/Test/Unit/Model/Product/RequestTest.php b/Test/Unit/Model/Product/RequestTest.php new file mode 100644 index 0000000..d152724 --- /dev/null +++ b/Test/Unit/Model/Product/RequestTest.php @@ -0,0 +1,33 @@ +assertSame(42, $request->getId()); + } + + public function testGetOverwriteReturnsTrue(): void + { + $request = new Request(1, true); + $this->assertTrue($request->getOverwrite()); + } + + public function testGetOverwriteReturnsFalse(): void + { + $request = new Request(1, false); + $this->assertFalse($request->getOverwrite()); + } +} diff --git a/Test/Unit/Trait/ProductMockTrait.php b/Test/Unit/Trait/ProductMockTrait.php new file mode 100644 index 0000000..4002bcf --- /dev/null +++ b/Test/Unit/Trait/ProductMockTrait.php @@ -0,0 +1,71 @@ + */ + private array $productSetDataCalls = []; + + /** + * Create a Product mock with configurable data, ID, and store ID. + * + * @param array $attributes Data returned by getData() + * @param int|null $id Product ID (falls back to $attributes['entity_id']) + * @param int|null $storeId Store ID (falls back to $attributes['store_id'], then 0) + * @param bool $trackSetData When true, setData() calls are recorded in $productSetDataCalls + * @return Product&MockObject + */ + protected function createProductMock( + array $attributes = [], + ?int $id = null, + ?int $storeId = null, + bool $trackSetData = false + ): Product&MockObject { + $product = $this->getMockBuilder(Product::class) + ->disableOriginalConstructor() + ->getMock(); + + $product->method('getData') + ->willReturnCallback(function (?string $key = null) use ($attributes) { + if ($key === null) { + return $attributes; + } + return $attributes[$key] ?? null; + }); + + $product->method('getId')->willReturn($id ?? ($attributes['entity_id'] ?? null)); + $product->method('getStoreId')->willReturn($storeId ?? ($attributes['store_id'] ?? 0)); + + if ($trackSetData) { + $this->productSetDataCalls = []; + $product->method('setData') + ->willReturnCallback(function (string $key, $value) use ($product) { + $this->productSetDataCalls[] = ['key' => $key, 'value' => $value]; + return $product; + }); + } + + return $product; + } + + /** + * @return array + */ + protected function getProductSetDataCalls(): array + { + return $this->productSetDataCalls; + } +} diff --git a/Test/Unit/bootstrap.php b/Test/Unit/bootstrap.php new file mode 100644 index 0000000..29a69eb --- /dev/null +++ b/Test/Unit/bootstrap.php @@ -0,0 +1,24 @@ + + + + + Test/Unit + + + + + + + +