Unit Tests
Test Directory Structure
Amazon/Prep/
├── Test/
│ ├── Unit/
│ │ ├── Model/
│ │ │ └── WarrantyTest.php
│ │ └── Service/
│ │ └── WarrantyServiceTest.php
│ └── Integration/
│ ├── Model/
│ │ └── WarrantyRepositoryTest.php
│ └── _files/
│ └── warranty_data.php
└── phpunit.xml
Basic Unit Test
<?php
namespace Amazon\Prep\Test\Unit\Model;
use PHPUnit\Framework\TestCase;
use Amazon\Prep\Model\Warranty;
class WarrantyTest extends TestCase
{
private Warranty $warranty;
protected function setUp(): void
{
$this->warranty = new Warranty();
}
public function testGetNameReturnsName(): void
{
$this->warranty->setName('Premium Warranty');
$this->assertEquals('Premium Warranty', $this->warranty->getName());
}
public function testGetDurationReturnsInteger(): void
{
$this->warranty->setDuration(24);
$this->assertEquals(24, $this->warranty->getDuration());
}
public function testDefaultStatusIsActive(): void
{
$this->warranty->setStatus('active');
$this->assertEquals('active', $this->warranty->getStatus());
}
}
Unit Test with Mocks
<?php
namespace Amazon\Prep\Test\Unit\Service;
use PHPUnit\Framework\TestCase;
use Amazon\Prep\Service\WarrantyService;
use Amazon\Prep\Model\WarrantyFactory;
use Amazon\Prep\Model\Warranty;
use Amazon\Prep\Model\ResourceModel\Warranty as WarrantyResource;
use Psr\Log\LoggerInterface;
class WarrantyServiceTest extends TestCase
{
private WarrantyService $service;
private $factoryMock;
private $resourceMock;
private $loggerMock;
protected function setUp(): void
{
$this->factoryMock = $this->createMock(WarrantyFactory::class);
$this->resourceMock = $this->createMock(WarrantyResource::class);
$this->loggerMock = $this->createMock(LoggerInterface::class);
$this->service = new WarrantyService(
$this->factoryMock,
$this->resourceMock,
$this->loggerMock
);
}
public function testCreateWarrantyReturnsWarranty(): void
{
$warranty = $this->createMock(Warranty::class);
$warranty->method('getId')->willReturn(1);
$this->factoryMock->method('create')->willReturn($warranty);
$this->resourceMock->method('save')->willReturnSelf();
$result = $this->service->createWarranty('Test', 12);
$this->assertInstanceOf(Warranty::class, $result);
$this->assertEquals(1, $result->getId());
}
public function testCreateWarrantySetsName(): void
{
$warranty = $this->createMock(Warranty::class);
$warranty->expects($this->once())
->method('setName')
->with('Premium Warranty')
->willReturnSelf();
$this->factoryMock->method('create')->willReturn($warranty);
$this->resourceMock->method('save')->willReturnSelf();
$this->service->createWarranty('Premium Warranty', 24);
}
}
Mock Methods
// Create mock
$mock = $this->createMock(ClassName::class);
// Set expectations
$mock->method('methodName')->willReturn('value');
$mock->expects($this->once())->method('methodName');
$mock->expects($this->exactly(3))->method('methodName');
// Argument matching
$mock->method('methodName')->with($this->equalTo('arg'));
$mock->method('methodName')->with($this->anything());
$mock->method('methodName')->with($this->stringContains('test'));
Integration Tests
Integration Test Setup
<?php
namespace Amazon\Prep\Test\Integration\Model;
use PHPUnit\Framework\TestCase;
use Magento\TestFramework\Helper\Bootstrap;
use Amazon\Prep\Api\WarrantyRepositoryInterface;
use Amazon\Prep\Api\Data\WarrantyInterfaceFactory;
use Magento\Framework\Api\SearchCriteriaBuilder;
class WarrantyRepositoryTest extends TestCase
{
private WarrantyRepositoryInterface $repository;
private WarrantyInterfaceFactory $warrantyFactory;
private SearchCriteriaBuilder $searchCriteriaBuilder;
protected function setUp(): void
{
$this->repository = Bootstrap::getObjectManager()
->get(WarrantyRepositoryInterface::class);
$this->warrantyFactory = Bootstrap::getObjectManager()
->get(WarrantyInterfaceFactory::class);
$this->searchCriteriaBuilder = Bootstrap::getObjectManager()
->get(SearchCriteriaBuilder::class);
}
public function testSaveAndGetWarranty(): void
{
$warranty = $this->warrantyFactory->create();
$warranty->setName('Integration Test Warranty');
$warranty->setDuration(12);
$warranty->setSku('TEST-001');
$warranty->setStatus(1);
$savedWarranty = $this->repository->save($warranty);
$this->assertNotNull($savedWarranty->getId());
$loadedWarranty = $this->repository->get($savedWarranty->getId());
$this->assertEquals('Integration Test Warranty', $loadedWarranty->getName());
// Cleanup
$this->repository->delete($savedWarranty);
}
public function testGetListReturnsResults(): void
{
$searchCriteria = $this->searchCriteriaBuilder
->addFilter('status', 1)
->setPageSize(10)
->create();
$searchResults = $this->repository->getList($searchCriteria);
$this->assertIsArray($searchResults->getItems());
$this->assertGreaterThanOrEqual(0, $searchResults->getTotalCount());
}
}
Integration Test with Fixtures
<?php
namespace Amazon\Prep\Test\Integration\Model;
use Magento\TestFramework\Fixture\RevertIsolation;
class WarrantyServiceTest extends TestCase
{
/**
* @fixture Amazon_Prep/Model/WarrantyFixture
*/
public function testProcessWarranty(): void
{
// Test with fixture data
}
}
Custom Fixture
<?php
namespace Amazon\Prep\Test\Integration\_files;
use Magento\TestFramework\Fixture\FixtureInterface;
class WarrantyFixture implements FixtureInterface
{
public function __construct(
private \Amazon\Prep\Api\Data\WarrantyInterfaceFactory $factory,
private \Amazon\Prep\Api\WarrantyRepositoryInterface $repository
) {}
public function load(): void
{
$warranty = $this->factory->create();
$warranty->setName('Fixture Warranty');
$warranty->setDuration(12);
$warranty->setSku('FIXTURE-001');
$this->repository->save($warranty);
}
}
Test Configuration
phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
bootstrap="../../../vendor/autoload.php"
colors="true"
verbose="true">
<testsuites>
<testsuite name="Unit Tests">
<directory suffix="Test.php">Test/Unit</directory>
</testsuite>
<testsuite name="Integration Tests">
<directory suffix="Test.php">Test/Integration</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory suffix=".php">Model</directory>
<directory suffix=".php">Service</directory>
<directory suffix=".php">Api</directory>
</include>
</coverage>
</phpunit>
Running Tests
# Unit tests only
bin/magento dev:tests:run-unit --filter Amazon_Prep
# Or with PHPUnit directly
./vendor/bin/phpunit -c dev/tests/unit/phpunit.xml
# Integration tests
bin/magento dev:tests:run --filter Amazon_Prep
# Specific test class
./vendor/bin/phpunit Test/Unit/Model/WarrantyTest.php
# With coverage
./vendor/bin/phpunit --coverage-html=coverage Test/Unit/
Test Helper Methods
// Assert equals
$this->assertEquals($expected, $actual);
// Assert contains
$this->assertStringContainsString('needle', $haystack);
// Assert count
$this->assertCount(3, $array);
// Assert exception
$this->expectException(NoSuchEntityException::class);
$this->repository->get(999);
// Assert no exception
$this->repository->get(1); // Should not throw
Testing Best Practices
Test Naming
// Method name: test + MethodBeingTested + Scenario + ExpectedResult
public function testGetNameReturnsNameWhenSet(): void
public function testSaveThrowsExceptionWhenInvalidData(): void
public function testGetListReturnsEmptyWhenNoRecords(): void
AAA Pattern
public function testCreateWarranty(): void
{
// Arrange
$name = 'Test Warranty';
$duration = 12;
// Act
$result = $this->service->createWarranty($name, $duration);
// Assert
$this->assertEquals($name, $result->getName());
$this->assertEquals($duration, $result->getDuration());
}
Test Data Builders
class WarrantyBuilder
{
private string $name = 'Default Warranty';
private int $duration = 12;
private string $sku = 'DEFAULT-001';
public function withName(string $name): self
{
$this->name = $name;
return $this;
}
public function withDuration(int $duration): self
{
$this->duration = $duration;
return $this;
}
public function build(): WarrantyInterface
{
$warranty = new Warranty();
$warranty->setName($this->name);
$warranty->setDuration($this->duration);
$warranty->setSku($this->sku);
return $warranty;
}
}
// Usage:
$warranty = (new WarrantyBuilder())
->withName('Premium')
->withDuration(24)
->build();
Common Test Scenarios
- Happy path — normal expected behavior
- Edge cases — empty inputs, zero values
- Error cases — invalid data, missing records
- Boundary values — min/max limits
- Null handling — null inputs and outputs
CI/CD Integration
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Tests
run: ./vendor/bin/phpunit -c phpunit.xml
Test Coverage Goals
- Unit tests: 80%+ line coverage
- Integration tests: critical paths
- Focus on business logic, not framework code
Quiz
1. What is the difference between unit and integration tests?
2. What does setUp() do in PHPUnit?
3. How do you run only unit tests for a module?
Flashcards
Question
What does PHPUnit's assert assertEquals do?
Click to reveal answer
Answer
Checks if two values are equal
Question
Where do unit tests live?
Click to reveal answer
Answer
Test/Unit/ directory in the module
Question
What is a test fixture?
Click to reveal answer
Answer
Predefined test data and state setup for tests
Question
How do you mock a class in PHPUnit?
Click to reveal answer
Answer
$this->createMock(ClassName::class)
Question
What is the AAA pattern?
Click to reveal answer
Answer
Arrange, Act, Assert — structure for test methods
Revision Notes
Key Takeaways
- 1. Unit tests mock dependencies; integration tests use real objects
- 2. Place tests in Test/Unit/ and Test/Integration/ directories
- 3. Use setUp() for test initialization, assert methods for verification
- 4. Follow AAA pattern: Arrange, Act, Assert
- 5. Aim for 80%+ unit test coverage on business logic
Interview Tips
- • Know the difference between unit and integration tests
- • Be ready to write a test with mocks for a service class
- • Discuss test coverage and testing strategies
- • Explain the AAA test pattern
Cheat Sheet
Unit test:
extends TestCase
$this->createMock()
$this->assertEquals()
$this->expectException()
Integration test:
Bootstrap::getObjectManager()
Test with real DB and services
Run:
./vendor/bin/phpunit Test/Unit/
bin/magento dev:tests:run-unit