Skip to content
intermediate Phase 73 · Testing Fundamentals

Integration Tests

1h
1 problems
Topic Progress 0%

Integration Test Database Setup

Test Database Configuration

// dev/tests/integration/etc/install-config.php
return [
    'db-host' => 'localhost',
    'db-user' => 'root',
    'db-password' => '',
    'db-name' => 'magento_integration_tests',
    'db-engine' => 'mysql',
    'backend-frontname' => 'backend',
    'admin-email' => 'admin@example.com',
    'admin-user' => 'admin',
    'admin-password' => 'admin123',
    'language' => 'en_US',
    'currency' => 'USD',
    'timezone' => 'America/Chicago',
];

PHPUnit Integration Config

<!-- dev/tests/integration/phpunit.xml.dist -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="../bootstrap.php"
         colors="true">
    <testsuites>
        <testsuite name="Magento Integration Tests">
            <directory>../../../app/code/Vendor/Module/Test/Integration</directory>
        </testsuite>
    </testsuites>
    <php>
        <env name="MAGE_MODE" value="developer" />
        <env name="APP_ENV" value="integration_test" />
    </php>
</phpunit>

Running Integration Tests

# Setup test database
bin/magento setup:install --db-name=magento_integration_tests

# Run integration tests
vendor/bin/phpunit -c dev/tests/integration/phpunit.xml.dist

# Run with coverage
vendor/bin/phpunit --coverage-html dev/tests/integration/coverage \
    -c dev/tests/integration/phpunit.xml.dist

Key Points

  • Integration tests use a real database
  • Tests should be isolated and not affect each other
  • Use transactions for test isolation
  • Clean up test data after each test

Test Fixtures

File-Based Fixtures

// dev/tests/integration/fixtures/product.json
[
    {
        "sku": "TEST-PRODUCT-001",
        "name": "Test Product",
        "price": 99.99,
        "status": 1,
        "visibility": 4,
        "type_id": "simple",
        "attribute_set_id": 4
    }
]

PHP Fixtures

// dev/tests/integration/fixtures/category.php
<?php
return [
    'category' => [
        'name' => 'Test Category',
        'is_active' => 1,
        'path' => '1/2/3',
        'level' => 2,
        'position' => 1,
    ],
];

Fixture Loading in Tests

namespace Vendor\Module\Test\Integration\Model;

use PHPUnit\Framework\TestCase;
use Magento\TestFramework\Helper\Bootstrap;

class ProductRepositoryTest extends TestCase
{
    /**
     * @magentoDbIsolation enabled
     * @magentoAppIsolation enabled
     * @magentoDataFixture product.json
     */
    public function testFindProduct()
    {
        $repository = Bootstrap::getObjectManager()
            ->create(\Magento\Catalog\Model\ProductRepository::class);

        $product = $repository->get('TEST-PRODUCT-001');

        $this->assertEquals('Test Product', $product->getName());
        $this->assertEquals(99.99, $product->getPrice());
    }
}

Key Points

  • Fixtures provide consistent test data
  • Use annotations to load fixtures
  • Fixtures can be JSON or PHP files
  • Keep fixtures minimal and focused

Setup and Teardown

Test Lifecycle

namespace Vendor\Module\Test\Integration\Model;

use PHPUnit\Framework\TestCase;
use Magento\TestFramework\Helper\Bootstrap;

class OrderTest extends TestCase
{
    protected function setUp(): void
    {
        // Initialize test environment
        $this->objectManager = Bootstrap::getObjectManager();
        $this->orderFactory = $this->objectManager->get(
            \Magento\Sales\Model\OrderFactory::class
        );
    }

    protected function tearDown(): void
    {
        // Clean up test data
        $this->objectManager->get(
            \Magento\Framework\App\ResourceConnection::class
        )->getConnection()->rollBack();
    }

    public function testCreateOrder()
    {
        $order = $this->orderFactory->create();
        $order->setData([
            'increment_id' => '100000001',
            'customer_id' => 1,
            'status' => 'pending',
        ]);
        $order->save();

        $this->assertNotEmpty($order->getId());
    }
}

Global Setup/Teardown

// dev/tests/integration/setup.sh
#!/bin/bash

# Create test database
mysql -u root -e "CREATE DATABASE IF NOT EXISTS magento_integration_tests;"

# Install Magento
bin/magento setup:install \
    --db-name=magento_integration_tests \
    --admin-user=admin \
    --admin-password=admin123 \
    --backend-frontname=backend

# Create admin user
bin/magento admin:user:create \
    --admin-user=admin \
    --admin-password=admin123 \
    --admin-email=admin@example.com

Key Points

  • setUp() runs before each test method
  • tearDown() runs after each test method
  • Use transactions for quick cleanup
  • Global setup runs once for entire test suite

Test Isolation

Database Isolation

namespace Vendor\Module\Test\Integration\Model;

use PHPUnit\Framework\TestCase;
use Magento\TestFramework\Helper\Bootstrap;

class CustomerTest extends TestCase
{
    /**
     * @magentoDbIsolation enabled
     */
    public function testCreateCustomer()
    {
        $customer = Bootstrap::getObjectManager()->create(
            \Magento\Customer\Model\Customer::class
        );
        $customer->setData([
            'email' => 'test@example.com',
            'firstname' => 'Test',
            'lastname' => 'Customer',
        ]);
        $customer->save();

        // This change is rolled back after test
        $this->assertNotEmpty($customer->getId());
    }
}

Application Isolation

/**
 * @magentoAppIsolation enabled
 */
public function testWithDifferentConfig()
{
    // This test gets a fresh application instance
    $config = Bootstrap::getObjectManager()->get(
        \Magento\Framework\App\Config\ReinitableConfigInterface::class
    );
    $config->reinit();

    // Modify configuration
    $this->objectManager->get(
        \Magento\Framework\App\Config\ValueInterface::class
    )->setValue('test/value', 'new_value')->save();

    // Test with new config
}

Key Points

  • @magentoDbIsolation wraps tests in transactions
  • @magentoAppIsolation provides fresh application instance
  • Use isolation for tests that modify state
  • Consider performance impact of isolation

Practice Problems

0 / 1 solved
Integration Test Suite

Create an integration test that verifies product creation and retrieval.

Solution
<?php
namespace Vendor\Module\Test\Integration\Model;

use PHPUnit\Framework\TestCase;
use Magento\TestFramework\Helper\Bootstrap;

class ProductIntegrationTest extends TestCase
{
    /**
     * @magentoDbIsolation enabled
     */
    public function testCreateAndRetrieveProduct()
    {
        $objectManager = Bootstrap::getObjectManager();
        $productFactory = $objectManager->get(
            \Magento\Catalog\Model\ProductFactory::class
        );
        
        // Create product
        $product = $productFactory->create();
        $product->setData([
            'sku' => 'INT-TEST-001',
            'name' => 'Integration Test Product',
            'price' => 49.99,
            'status' => 1,
            'visibility' => 4,
            'type_id' => 'simple',
            'attribute_set_id' => 4,
        ]);
        $product->save();
        
        // Retrieve product
        $repository = $objectManager->get(
            \Magento\Catalog\Model\ProductRepository::class
        );
        $retrieved = $repository->get('INT-TEST-001');
        
        $this->assertEquals('Integration Test Product', $retrieved->getName());
        $this->assertEquals(49.99, $retrieved->getPrice());
    }
}

Quiz

1. What does @magentoDbIsolation do?

Question 1 options

2. How are fixtures loaded?

Question 2 options

3. What is the test database for?

Question 3 options

4. When does tearDown() execute?

Question 4 options

Flashcards

Question

@magentoDbIsolation?

Answer

Wraps test in transaction, rolls back after

Question

Load fixture annotation?

Answer

@magentoDataFixture filename.json

Question

Integration test DB?

Answer

Separate database for isolated testing

Question

tearDown() purpose?

Answer

Clean up after each test method

Revision Notes

Key Takeaways

  • 1. Integration tests use a separate test database
  • 2. Use @magentoDbIsolation for transaction-based cleanup
  • 3. Fixtures provide consistent test data
  • 4. Test isolation prevents interference between tests

Interview Tips

  • Explain the difference between unit and integration tests
  • Discuss test isolation strategies
  • Know how Magento test fixtures work

Cheat Sheet

Integration Tests

  • DB: separate test database
  • Isolation: @magentoDbIsolation
  • Fixtures: @magentoDataFixture
  • Setup: setUp()/tearDown()
  • Config: dev/tests/integration/