VOOZH about

URL: https://deepwiki.com/guanguans/ai-commit/6.2-testing-framework

⇱ Testing Framework | guanguans/ai-commit | DeepWiki


Loading...
Menu

Testing Framework

This page documents the test suite structure, tooling, and conventions used in the ai-commit codebase. It covers how Pest is configured, the base TestCase class, HTTP simulation helpers, PHPMock integration, and how to run tests. For information about the CI workflows that execute these tests automatically, see CI/CD Workflows. For development environment setup, see Development Environment Setup.


Overview

The test suite uses Pest as the test runner, backed by PHPUnit. Tests are split into two suites — Feature and Unit — and use Laravel Zero's testing infrastructure via LaravelZero\Framework\Testing\TestCase.

tests/
├── Datasets/
│ └── CommitCommandParameters.php
├── Feature/
│ ├── CommitCommandTest.php
│ └── ConfigCommandTest.php
├── Fixtures/
│ ├── ai-commit.json (invalid JSON fixture)
│ ├── ai-commit.yml (unsupported format fixture)
│ └── repository/ (git repo used in integration tests)
├── Unit/
│ ├── ConfigManagerTest.php
│ ├── GeneratorManagerTest.php
│ └── Generators/
│ ├── BitoGeneratorTest.php
│ ├── MoonshotGeneratorTest.php
│ ├── OpenAIChatGeneratorTest.php
│ └── OpenAIGeneratorTest.php
├── Pest.php
└── TestCase.php

Sources: tests/Pest.php39-43 phpunit.xml.dist9-18


PHPUnit Configuration

The phpunit.xml.dist file defines two named test suites and the source code coverage scope.

SettingValue
Bootstrapvendor/autoload.php
Cache directory.build/phpunit/
Feature suite directory./tests/Feature
Unit suite directory./tests/Unit
Coverage source: included./app, ./bootstrap
Coverage source: excludedapp/Support/helpers.php
APP_ENVtesting
DB_CONNECTIONsqlite
DB_DATABASE:memory:

Sources: phpunit.xml.dist1-42


Test Suite Structure

Test suite layout — suites, files, and what they test


Sources: phpunit.xml.dist9-18 tests/Pest.php39-43

Feature Tests

Feature tests exercise full command execution using Laravel Zero's $this->artisan(...) helper. They interact with the running application container, real ConfigManager state, and optionally a real git repository under tests/Fixtures/repository/.

Key scenarios in CommitCommandTest.php:

  • Asserts ProcessFailedException when path is not a git repository.
  • Asserts RuntimeException when there are no staged files.
  • Simulates a full commit flow using setup_http_fake() and interactive prompt expectations.

Key scenarios in ConfigCommandTest.php:

  • Tests all config actions: set, get, unset, reset, list, edit.
  • Uses PHPMock to stub file_exists in the ConfigCommand namespace.
  • Uses Mockery to substitute ExecutableFinder for editor-not-found edge cases.

Sources: tests/Feature/CommitCommandTest.php29-103 tests/Feature/ConfigCommandTest.php30-162

Unit Tests

Unit tests target individual classes in isolation, typically resolving them from the service container with app(ClassName::class).

FilePrimary Class Under TestKey Assertions
ConfigManagerTest.phpConfigManagerinstantiation, JSON errors, unsupported file type
GeneratorManagerTest.phpGeneratorManagerdriver resolution, custom driver extension
OpenAIGeneratorTest.phpOpenAIGeneratorHTTP success, 401/403 errors, streaming writer
OpenAIChatGeneratorTest.phpOpenAIChatGeneratorHTTP success, request count
MoonshotGeneratorTest.phpMoonshotGeneratorHTTP success, 401/403 errors, streaming writer
BitoGeneratorTest.phpBitoCliGeneratorProcessFailedException when binary not found

Sources: tests/Unit/ConfigManagerTest.php29-72 tests/Unit/GeneratorManagerTest.php29-55 tests/Unit/Generators/OpenAIGeneratorTest.php31-80


Base TestCase Class

All tests share a common base class: Tests\TestCase, which extends LaravelZero\Framework\Testing\TestCase.

Class: Tests\TestCase

FeatureDetail
ExtendsLaravelZero\Framework\Testing\TestCase
TraitsMockeryPHPUnitIntegration, PHPMock
setUp()Initializes Mockery, loads ConfigManager from config/ai-commit.php, seeds test API keys
tearDown()Calls $this->finish(), closes Mockery, calls parent::tearDown()

In setUp(), the ConfigManager is initialized from the application config and injected with safe test values:

generators.openai.api_key = "sk-..."
generators.bito_cli.path = "bito-cli-path..."

This prevents tests from accidentally using real credentials while keeping the config structure intact.

Sources: tests/TestCase.php35-68


Pest Bootstrap (tests/Pest.php)

tests/Pest.php is the central Pest configuration file. It wires TestCase as the base for all tests in tests/Feature and tests/Unit, registers lifecycle hooks, defines custom expectations, and declares global helper functions.

Lifecycle hooks (applied to all tests in both suites):

HookAction
beforeAllempty (reserved)
beforeEachPrepends v to app.version config value
afterEachempty (reserved)
afterAllempty (reserved)

Custom expectations added via expect()->extend():

ExpectationSignatureBehavior
toAsserttoAssert(Closure $assertions)Runs arbitrary assertion closure on the value
toBetweentoBetween(int $min, int $max)Asserts value is within an inclusive integer range

Sources: tests/Pest.php31-65


Global Test Helper Functions

Several utility functions are defined in tests/Pest.php and available globally in all test files.

Test helper functions — name to definition mapping



































FunctionUsage
class_namespace($class)Returns the PHP namespace of a class; used with PHPMock::getFunctionMock() to target the right namespace
repository_path($path)Returns an absolute path inside tests/Fixtures/repository/ — the embedded git repo used for integration tests
fixtures_path($path)Returns an absolute path inside tests/Fixtures/ — for fixture files like ai-commit.json and ai-commit.yml
running_in_github_action()Returns true when the GITHUB_ACTIONS environment variable is 'true'
reset_http_fake($factory)Resets stub callbacks on the Http facade to clear previously registered fakes
setup_http_fake()Registers Http::fake() stubs for all AI API endpoints (see below)

Sources: tests/Pest.php80-108 tests/Pest.php109-216


HTTP Fake Layer (setup_http_fake)

setup_http_fake() is the primary mechanism for simulating AI API responses in tests. It registers URL pattern-based response handlers using Laravel's Http::fake().

HTTP fakes registered by setup_http_fake()

URL PatternSimulated ServiceBehavior
*://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/*ErnieBot / ErnieBotTurboReturns success or error JSON based on prompt content
*://aip.baidubce.com/oauth/2.0/token?*Baidu OAuthReturns a fixed access token JSON
*://api.moonshot.cn/v1/chat/completionsMoonshotGeneratorReturns success or error based on prompt
*://api.moonshot.cn/v1/modelsMoonshot models listReturns static model list
*://api.openai.com/v1/completionsOpenAIGeneratorReturns success with commit JSON or error
*://api.openai.com/v1/chat/completionsOpenAIChatGeneratorReturns success or error
*://api.openai.com/v1/modelsOpenAI models listReturns static model list

Status code simulation: Each handler inspects the prompt text and maps it to an HTTP status code by looking it up in Symfony\Component\HttpFoundation\Response::$statusTexts. Sending the string "Forbidden" as the prompt triggers a 403 response; "Unauthorized" triggers 401; any other string returns 200.

Example trigger pattern:

// In a test:
app(GeneratorManager::class)->driver('openai')->generate('Forbidden');
// → Http fake sees prompt = "Forbidden" → status 403 → RequestException thrown

Data flow through setup_http_fake


Sources: tests/Pest.php109-216 tests/Unit/Generators/OpenAIGeneratorTest.php27-46 tests/Unit/Generators/MoonshotGeneratorTest.php27-47


PHPMock Integration

Tests\TestCase includes the phpmock\phpunit\PHPMock trait, which enables mocking of built-in PHP functions within specific namespaces.

Pattern used:


  • class_namespace(ConfigCommand::class) resolves to App\Commands using ReflectionClass.
  • getFunctionMock('App\Commands', 'file_exists') creates a mock that intercepts calls to file_exists only within the App\Commands namespace.

This technique is used in ConfigCommandTest.php to simulate the absence of the local config file without needing to delete or modify any real file.

Sources: tests/TestCase.php43-44 tests/Feature/ConfigCommandTest.php31-33 tests/Pest.php80-85


Mockery Integration

Tests\TestCase includes Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration, which automatically calls Mockery::close() at the end of each test through $this->closeMockery().

Mockery is used in feature tests to substitute service container bindings for testing edge cases:


Sources: tests/TestCase.php43 tests/Feature/ConfigCommandTest.php143-156


Datasets

Pest datasets provide parameterized test inputs. The one declared dataset is:

File: tests/Datasets/CommitCommandParameters.php
Dataset name: 'commit command parameters'

CaseParameters
Default[] (no extra flags)
Dry run['--dry-run' => true]
Custom diff['--diff' => '<inline diff string>']

This dataset is consumed in CommitCommandTest.php with the .with('commit command parameters') modifier, causing the commit generation test to run three times with each parameter set.

Sources: tests/Datasets/CommitCommandParameters.php23-40 tests/Feature/CommitCommandTest.php91-93


Test Execution Flow

Full lifecycle from a single test's perspective


Sources: tests/TestCase.php47-65 tests/Pest.php32-43


Running Tests

Run all tests:


Run a specific suite:


Run a specific file:


Run tests in a specific group (groups are file paths set by .group(__DIR__, __FILE__)):


Generate code coverage (requires Xdebug or PCOV):


Sources: phpunit.xml.dist1-42 tests/Unit/Generators/OpenAIGeneratorTest.php35