Pular para o conteúdo

Estratégia de testes

merql usa um modelo de testes orientado por oráculo. Cada cenário de teste define um conjunto conhecido de entradas (três estados do banco de dados), um resultado esperado determinístico (o oráculo) e compara a saída real da mesclagem com essa expectativa. 32 cenários abrangem mesclagens sem conflitos, conflitos, resolução de identidade, tipos de dados, escala e casos extremos.

Shell
# Run the full verification suite.
./bin/verify-all

Os comandos desta página são executados a partir de um checkout do repositório merql após composer install. Os scripts de desenvolvimento em bin/, o corpus de scenarios/ e os testes não fazem parte do pacote Composer. As dependências de desenvolvimento incluem PHPUnit 13, que requer PHP 8.4 ou posterior, embora a biblioteca em si seja executada em PHP 8.2.

Testes orientados por oráculo

Não existe uma ferramenta de referência que faça mesclagem de banco de dados em três vias, portanto o oráculo é calculado a partir de entradas conhecidas, em vez de ser gerado por uma ferramenta externa. Cada cenário tem um resultado esperado determinístico que pode ser verificado por lógica:

  1. Configuração -- crie três estados do banco de dados (base, ours, theirs) com conteúdo conhecido.
  2. Oráculo -- calcule o resultado esperado da mesclagem a partir das entradas conhecidas.
  3. Resultado real -- execute a mesclagem do merql nos três estados.
  4. Comparação -- o resultado real deve corresponder exatamente ao resultado esperado.
Código
Known inputs (base, ours, theirs)
         |                    |
    Deterministic          merql merge
    computation
         |                    |
    Expected result       Actual result
         |                    |
         -----> Compare <-----
                  |
            Pass or Fail

Executar testes

Verificação completa

O script verify-all é a etapa final de validação. Ele executa análise estática, padrões de código, testes PHPUnit e o conjunto de regressão do oráculo:

Shell
./bin/verify-all

Isso deve passar antes que qualquer trabalho seja considerado concluído.

Conjunto de regressão do oráculo

Execute todos os 32 cenários:

Shell
./bin/test-regression

Execute uma única categoria:

Shell
./bin/test-regression --category clean
./bin/test-regression --category conflict
./bin/test-regression --category identity

As categorias são os nomes dos diretórios em scenarios/: clean, conflict, identity, types, scale e edge. Uma categoria desconhecida exibe No scenarios found e termina com sucesso. --category pode ser repetido para executar várias categorias.

O script também aceita --jobs, mas ignora o valor e executa os cenários um após o outro (#5).

Execute com saída mínima (somente aprovação/reprovação):

Shell
./bin/test-regression --fast

Cenário único

Teste um cenário por meio do pipeline completo:

Shell
./bin/test-scenario column-level-clean

Etapas individuais do oráculo

Shell
./bin/oracle column-level-clean    # Compute expected result
./bin/actual column-level-clean    # Run merql, capture output
./bin/compare column-level-clean   # Diff oracle vs actual

Testes unitários

Shell
composer test:unit         # Isolated component tests
composer test:integration  # Integration tests (SQLite, plus MySQL when configured)
composer test              # All PHPUnit suites
composer test:oracle       # Oracle regression corpus (bin/test-regression)
composer verify            # analyse + cs + test + test:oracle

composer test executa somente PHPUnit. O conjunto oracle PHPUnit aponta para tests/Oracle, que contém as classes do executor de cenários, mas nenhum caso de teste; por isso, os 32 cenários são executados apenas por meio de composer test:oracle, composer verify ou ./bin/verify-all.

Os testes de integração de MySQL são ignorados, a menos que MERQL_MYSQL_HOST, MERQL_MYSQL_DATABASE e MERQL_MYSQL_USER (e, opcionalmente, MERQL_MYSQL_PASSWORD e MERQL_MYSQL_PORT) apontem para um banco de dados de teste.

Qualidade do código

Shell
composer cs            # PSR-12 coding standards check
composer cs:fix        # Auto-fix coding standards
composer analyse       # PHPStan level 10 static analysis

Categorias de cenários

clean (8 cenários)

Mesclagens sem conflitos. Ambos os lados podem alterar dados, mas nunca a mesma coluna da mesma linha.

Cenário Testes
insert-only-theirs theirs inseriu linhas; ours não mudou.
update-only-theirs theirs atualizou linhas; ours não mudou.
delete-only-theirs theirs excluiu linhas; ours não mudou.
insert-only-ours ours inseriu linhas; theirs não mudou.
mixed-no-overlap Ambos alteraram tabelas ou linhas diferentes.
both-same-change Ambos fizeram alterações idênticas (sem conflito).
column-level-clean Ambos alteraram a mesma linha, em colunas diferentes.
multi-table Alterações em várias tabelas.

conflict (6 cenários)

Cenários que devem gerar conflitos.

Cenário Testes
both-update-same-column Ambos alteraram a mesma coluna para valores diferentes.
update-vs-delete Um atualizou e o outro excluiu a mesma linha.
delete-vs-update Direção inversa da atualização versus exclusão.
both-insert-same-pk Ambos inseriram uma linha com a mesma chave primária.
multiple-conflicts Vários conflitos em uma mesclagem.
partial-conflict Algumas colunas entram em conflito; outras são mescladas sem problemas.

identity (4 cenários)

Casos extremos de identidade de linha.

Cenário Testes
auto-increment Novas linhas têm IDs diferentes entre ramificações.
natural-key Associação por colunas únicas em vez de PK.
composite-key Chave primária com várias colunas.
no-key Tabela sem chave primária (alternativa de hash de conteúdo).

types (6 cenários)

Tratamento de tipos de dados em todos os tipos de coluna.

Cenário Testes
text-columns Valores VARCHAR, TEXT e LONGTEXT.
numeric-columns Valores INT, DECIMAL e FLOAT.
date-columns Valores DATE, DATETIME e TIMESTAMP.
json-columns Mesclagem da coluna JSON.
blob-columns Dados binários.
null-handling Transições de NULL para valor e de valor para NULL.

scale (4 cenários)

Desempenho sob carga.

Cenário Testes
1k-rows 1,000 linhas.
10k-rows 10,000 linhas.
100k-rows 100,000 linhas.
wide-table Tabela com mais de 50 colunas.

edge (4 cenários)

Casos extremos e condições de limite.

Cenário Testes
empty-changeset Sem alterações em um ou nos dois lados.
schema-mismatch Coluna adicionada ou removida entre snapshots.
encoding UTF-8, emojis e caracteres especiais.
large-text Valores muito grandes de TEXT/LONGTEXT.

Estrutura dos cenários

Cada cenário é um diretório em scenarios/<category>/<name>/ com uma configuração scenario.json:

JSON
{
    "name": "column-level-clean",
    "category": "clean",
    "description": "Both sides modify same row but different columns",
    "tables": ["test_posts"],
    "expectations": {
        "conflicts": 0,
        "operations": 3,
        "changeset_match": "exact",
        "merge_match": "exact",
        "sql_match": "semantic"
    }
}

Para cenários de conflito, os conflitos esperados são especificados em detalhes:

JSON
{
    "expectations": {
        "conflicts": 1,
        "conflict_details": [
            {
                "table": "test_posts",
                "primary_key": {"id": 42},
                "column": "title",
                "ours_value": "Welcome",
                "theirs_value": "Greetings"
            }
        ]
    }
}

Pipeline do ScenarioRunner

ScenarioRunner::run() coordena um único cenário:

  1. OracleCapture::compute() cria três snapshots a partir dos dados JSON do cenário e executa a mesclagem.
  2. ScenarioComparator::compare() verifica o resultado da mesclagem em relação aos valores esperados em scenario.json.
  3. Retorna aprovação/reprovação com uma lista de mensagens de falha.
PHP
use Merql\Tests\Oracle\ScenarioRunner;

$result = ScenarioRunner::run($scenario);
// ['name' => 'column-level-clean', 'pass' => true, 'failures' => []]

ScenarioRunner::runAll() executa todos os cenários em sequência:

PHP
$results = ScenarioRunner::runAll($scenarios);

Adicionar um novo cenário

  1. Crie um diretório: scenarios/<category>/<name>/.
  2. Crie scenario.json com os metadados e as expectativas do cenário.
  3. Defina os três estados do banco de dados na configuração JSON: dados base, alterações de ours e alterações de theirs.
  4. Execute o cenário: ./bin/test-scenario <name>.
  5. Verifique o conjunto completo: ./bin/verify-all.

Padrões de qualidade do código

merql exige:

  • PHPStan nível 10 -- análise estática rigorosa, sem exceções de baseline.
  • PSR-12 -- padrões de código verificados por phpcs.
  • Regressão do oráculo -- todos os 32 cenários devem passar.
  • Testes unitários -- testes isolados para cada componente.

O script verify-all executa as quatro verificações em sequência. Não se aceita aprovação parcial.

Integração contínua

A CI executa a verificação de padrões de código, PHPStan, composer test, o conjunto de testes de integração com MySQL 8.4 via mysqli, a cobertura das primitivas de mesclagem e composer audit em cada push e pull request para main. Ela não executa o corpus de regressão do oráculo (#6), então execute composer test:oracle ou ./bin/verify-all localmente antes de confiar em uma alteração.