diff --git a/phpunit/.github/workflows/testomatio.yml b/phpunit/.github/workflows/testomatio.yml new file mode 100644 index 0000000..731d106 --- /dev/null +++ b/phpunit/.github/workflows/testomatio.yml @@ -0,0 +1,45 @@ +name: PHPUnit Tests with Testomat.io + +on: + push: + branches: + - master + - main + pull_request: + branches: + - master + - main + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + extensions: mbstring, xml, ctype, json + coverage: none + + - name: Validate composer.json + run: composer validate --strict + + - name: Cache Composer packages + uses: actions/cache@v4 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-interaction + + - name: Run PHPUnit tests + env: + TESTOMATIO: ${{ secrets.TESTOMATIO }} + run: ./vendor/bin/phpunit diff --git a/phpunit/.gitignore b/phpunit/.gitignore new file mode 100644 index 0000000..0cac656 --- /dev/null +++ b/phpunit/.gitignore @@ -0,0 +1,7 @@ +/vendor/ +/build/ +/.phpunit.cache/ +.phpunit.result.cache +composer.lock +.env +.DS_Store diff --git a/phpunit/README.md b/phpunit/README.md new file mode 100644 index 0000000..92c7563 --- /dev/null +++ b/phpunit/README.md @@ -0,0 +1,243 @@ +# PHPUnit Example with Testomat.io + +This is an example project demonstrating how to integrate PHPUnit tests with Testomat.io using JUnit XML reports. + +## ๐Ÿ› ๏ธ Tech Stack + +| Tool | Description | +|------|-------------| +| [PHPUnit](https://phpunit.de/) | PHP testing framework | +| [Testomat.io](https://testomat.io/) | Test management system | +| PHP 8.0+ | Programming language | + +## Requirements + +### Required +- **PHP 8.0 or higher** - For running PHPUnit tests +- **[Composer](https://getcomposer.org)** - PHP package manager for installing dependencies + +### Optional (for Testomat.io integration) +- **Testomat.io API Key** - specific to your project + +### Installation Instructions + +#### Installing PHP + +**macOS:** +```bash +# Using Homebrew +brew install php + +# Verify installation +php --version +``` + +**Ubuntu/Debian:** +```bash +sudo apt update +sudo apt install php php-mbstring php-xml php-curl + +# Verify installation +php --version +``` + +**Windows:** +- Download PHP from [windows.php.net](https://windows.php.net/download/) +- Or use [XAMPP](https://www.apachefriends.org/) / [WAMP](https://www.wampserver.com/) + +#### Installing Composer + +**macOS/Linux:** +```bash +# Download and install +php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" +php composer-setup.php +php -r "unlink('composer-setup.php');" +sudo mv composer.phar /usr/local/bin/composer + +# Verify installation +composer --version +``` + +**Windows:** +- Download installer from [getcomposer.org](https://getcomposer.org/download/) +- Run the installer and follow instructions + +#### Installing Node.js + +**macOS:** +```bash +# Using Homebrew +brew install node + +# Verify installation +node --version +npm --version +``` + +**Ubuntu/Debian:** +```bash +# Using NodeSource repository +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt-get install -y nodejs + +# Verify installation +node --version +npm --version +``` + +**Windows:** +- Download installer from [nodejs.org](https://nodejs.org/) +- Run the installer and follow instructions + +## โš™๏ธ Installation + +Clone the examples repository and navigate to the phpunit directory: + +```bash +git clone https://github.com/testomatio/examples.git +cd examples/phpunit +``` + +Install dependencies: + +```bash +composer install +``` + +## ๐Ÿƒโ€โ™‚๏ธ Running Tests + +Run all tests: + +```bash +./vendor/bin/phpunit +``` + +Run tests with verbose output: + +```bash +./vendor/bin/phpunit --testdox +``` + +Run specific test file: + +```bash +./vendor/bin/phpunit tests/CalculatorTest.php +``` + +## ๐Ÿ“Š Integration with Testomat.io + +This project uses the native **Testomat.io PHP Reporter** to report results directly. + +### Step 1: Install Reporter + +The reporter is included in `composer.json`. If you need to install it manually: + +```bash +composer require --dev testomatio/reporter +``` + +### Step 2: Configure PHPUnit + +The reporter is enabled in `phpunit.xml`: + +```xml + + + +``` + +### Step 3: Run Tests and Report Results + +Run tests passing the `TESTOMATIO` environment variable: + +```bash +TESTOMATIO={your-api-key} ./vendor/bin/phpunit +``` + +### Step 4: Import Test Structure + +To import test structure into Testomat.io: + +```bash +TESTOMATIO={your-api-key} ./vendor/bin/phpunit --list-tests +``` +Note: The reporter captures the list of tests and uploads them when the API key is present. + +> **Environment Variables**: It is recommended to store the Testomat.io API Key as an environment variable and never save it in source code. + +### Note on Data Providers + +PHPUnit's data providers create multiple test executions from a single test method. In this example: +- PHPUnit executes **22 tests** (13 test methods with data provider variations) +- JUnit XML report contains all 22 test case entries +- Testomat.io may show fewer tests due to how it parses nested `` elements for data providers + +This is expected behavior when using data providers with JUnit XML format. All test results are captured correctly. + +## ๐Ÿ“ Test Examples + +This project includes: + +### CalculatorTest.php +- Basic arithmetic operations (add, subtract, multiply, divide) +- Exception handling (division by zero) +- Data providers for parameterized tests +- Edge cases with negative and decimal numbers + +### UserRegistrationTest.php +- Email validation +- Password strength validation +- Username validation with data providers + +## ๐Ÿ”„ CI/CD Integration + +The project includes a GitHub Actions workflow (`.github/workflows/testomatio.yml`) that: + +1. Sets up PHP environment +2. Installs Composer dependencies +3. Runs PHPUnit tests +4. Generates JUnit XML report +5. Uploads results to Testomat.io + +To use it, add these secrets to your GitHub repository: +- `TESTOMATIO` - Your Testomat.io API key +- `TESTOMATIO_URL` - Your Testomat.io instance URL (optional) + +## ๐Ÿ“– Test Annotations + +Tests can be annotated with Testomat.io IDs in docblocks: + +```php +/** + * Test description + * @testomatio @T123abc + */ +public function testExample(): void +{ + // test code +} +``` + +## ๐Ÿงช Project Structure + +``` +phpunit/ +โ”œโ”€โ”€ src/ +โ”‚ โ””โ”€โ”€ Calculator.php # Example class to test +โ”œโ”€โ”€ tests/ +โ”‚ โ”œโ”€โ”€ CalculatorTest.php # Unit tests +โ”‚ โ””โ”€โ”€ UserRegistrationTest.php # Feature tests +โ”œโ”€โ”€ build/ +โ”‚ โ””โ”€โ”€ logs/ +โ”‚ โ””โ”€โ”€ junit.xml # Generated test report +โ”œโ”€โ”€ composer.json # PHP dependencies +โ”œโ”€โ”€ phpunit.xml # PHPUnit configuration +โ””โ”€โ”€ README.md # This file +``` + +## ๐Ÿ“š Learn More + +- [PHPUnit Documentation](https://docs.phpunit.de/) +- [Testomat.io Documentation](https://docs.testomat.io/) +- [JUnit XML Format](https://llg.cubic.org/docs/junit/) diff --git a/phpunit/composer.json b/phpunit/composer.json new file mode 100644 index 0000000..93e5ace --- /dev/null +++ b/phpunit/composer.json @@ -0,0 +1,26 @@ +{ + "name": "testomatio/phpunit-example", + "description": "PHPUnit example project with Testomat.io integration", + "type": "project", + "license": "MIT", + "require": { + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0", + "testomatio/reporter": "^1.0" + }, + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "tests/" + } + }, + "config": { + "sort-packages": true + } +} diff --git a/phpunit/phpunit.xml b/phpunit/phpunit.xml new file mode 100644 index 0000000..ffb1989 --- /dev/null +++ b/phpunit/phpunit.xml @@ -0,0 +1,23 @@ + + + + + tests + + + + + + + + src + + + + + + diff --git a/phpunit/report/junit.xml b/phpunit/report/junit.xml new file mode 100644 index 0000000..5c4d5af --- /dev/null +++ b/phpunit/report/junit.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phpunit/src/Calculator.php b/phpunit/src/Calculator.php new file mode 100644 index 0000000..aebff5c --- /dev/null +++ b/phpunit/src/Calculator.php @@ -0,0 +1,51 @@ +calculator = new Calculator(); + } + + /** + * Test basic addition + * @testomatio @T01 + */ + public function testAddition(): void + { + $result = $this->calculator->add(5, 3); + $this->assertEquals(8, $result); + } + + /** + * Test addition with negative numbers + * @testomatio @T02 + */ + public function testAdditionWithNegativeNumbers(): void + { + $result = $this->calculator->add(-5, 3); + $this->assertEquals(-2, $result); + } + + /** + * Test subtraction + * @testomatio @T03 + */ + public function testSubtraction(): void + { + $result = $this->calculator->subtract(10, 4); + $this->assertEquals(6, $result); + } + + /** + * Test multiplication + * @testomatio @T04 + */ + public function testMultiplication(): void + { + $result = $this->calculator->multiply(6, 7); + $this->assertEquals(42, $result); + } + + /** + * Test division + * @testomatio @T05 + */ + public function testDivision(): void + { + $result = $this->calculator->divide(15, 3); + $this->assertEquals(5, $result); + } + + /** + * Test division by zero throws exception + * @testomatio @T06 + */ + public function testDivisionByZeroThrowsException(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Division by zero is not allowed'); + $this->calculator->divide(10, 0); + } + + /** + * Test addition with positive numbers + * @testomatio @T07a + */ + public function testAdditionWithPositiveNumbers(): void + { + $result = $this->calculator->add(2, 3); + $this->assertEquals(5, $result); + } + + /** + * Test addition with negative numbers + * @testomatio @T07b + */ + public function testAdditionWithNegatives(): void + { + $result = $this->calculator->add(-2, -3); + $this->assertEquals(-5, $result); + } + + /** + * Test addition with mixed positive and negative numbers + * @testomatio @T07c + */ + public function testAdditionWithMixedNumbers(): void + { + $result = $this->calculator->add(10, -5); + $this->assertEquals(5, $result); + } + + /** + * Test addition with decimal numbers + * @testomatio @T07d + */ + public function testAdditionWithDecimals(): void + { + $result = $this->calculator->add(1.5, 2.5); + $this->assertEquals(4.0, $result); + } + + /** + * Test addition with zero + * @testomatio @T07e + */ + public function testAdditionWithZero(): void + { + $result = $this->calculator->add(0, 5); + $this->assertEquals(5, $result); + } + + /** + * Test percentage calculation + * @testomatio @T08 + */ + public function testPercentage(): void + { + $result = $this->calculator->percentage(200, 15); + $this->assertEquals(30, $result); + } +} diff --git a/phpunit/tests/UserRegistrationTest.php b/phpunit/tests/UserRegistrationTest.php new file mode 100644 index 0000000..fd0280f --- /dev/null +++ b/phpunit/tests/UserRegistrationTest.php @@ -0,0 +1,135 @@ +assertTrue($this->isValidEmail($email)); + } + + /** + * Test invalid email format + * @testomatio @T10 + */ + public function testInvalidEmailFormat(): void + { + $email = 'invalid-email'; + $this->assertFalse($this->isValidEmail($email)); + } + + /** + * Test password strength - strong password + * @testomatio @T11 + */ + public function testStrongPassword(): void + { + $password = 'SecureP@ss123'; + $this->assertTrue($this->isStrongPassword($password)); + } + + /** + * Test password strength - weak password + * @testomatio @T12 + */ + public function testWeakPassword(): void + { + $password = 'weak'; + $this->assertFalse($this->isStrongPassword($password)); + } + + /** + * Test username validation - valid username + * @testomatio @T13a + */ + public function testUsernameValidationWithValidUsername(): void + { + $result = $this->isValidUsername('john_doe'); + $this->assertTrue($result); + } + + /** + * Test username validation - valid alphanumeric + * @testomatio @T13b + */ + public function testUsernameValidationWithAlphanumeric(): void + { + $result = $this->isValidUsername('user123'); + $this->assertTrue($result); + } + + /** + * Test username validation - too short + * @testomatio @T13c + */ + public function testUsernameValidationTooShort(): void + { + $result = $this->isValidUsername('ab'); + $this->assertFalse($result); + } + + /** + * Test username validation - with spaces + * @testomatio @T13d + */ + public function testUsernameValidationWithSpaces(): void + { + $result = $this->isValidUsername('john doe'); + $this->assertFalse($result); + } + + /** + * Test username validation - special characters + * @testomatio @T13e + */ + public function testUsernameValidationWithSpecialChars(): void + { + $result = $this->isValidUsername('john@doe'); + $this->assertFalse($result); + } + + /** + * Test username validation - empty string + * @testomatio @T13f + */ + public function testUsernameValidationEmpty(): void + { + $result = $this->isValidUsername(''); + $this->assertFalse($result); + } + + // Helper methods simulating validation logic + + private function isValidEmail(string $email): bool + { + return filter_var($email, FILTER_VALIDATE_EMAIL) !== false; + } + + private function isStrongPassword(string $password): bool + { + // Password must be at least 8 characters with uppercase, lowercase, number, and special char + return strlen($password) >= 8 + && preg_match('/[A-Z]/', $password) + && preg_match('/[a-z]/', $password) + && preg_match('/[0-9]/', $password) + && preg_match('/[@$!%*?&#]/', $password); + } + + private function isValidUsername(string $username): bool + { + // Username must be 3-20 alphanumeric characters or underscore + return preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username) === 1; + } +}