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.
# 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:
- Configuração -- crie três estados do banco de dados (base, ours, theirs) com conteúdo conhecido.
- Oráculo -- calcule o resultado esperado da mesclagem a partir das entradas conhecidas.
- Resultado real -- execute a mesclagem do merql nos três estados.
- Comparação -- o resultado real deve corresponder exatamente ao resultado esperado.
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:
./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:
./bin/test-regression
Execute uma única categoria:
./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):
./bin/test-regression --fast
Cenário único
Teste um cenário por meio do pipeline completo:
./bin/test-scenario column-level-clean
Etapas individuais do oráculo
./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
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
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:
{
"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:
{
"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:
OracleCapture::compute()cria três snapshots a partir dos dados JSON do cenário e executa a mesclagem.ScenarioComparator::compare()verifica o resultado da mesclagem em relação aos valores esperados emscenario.json.- Retorna aprovação/reprovação com uma lista de mensagens de falha.
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:
$results = ScenarioRunner::runAll($scenarios);
Adicionar um novo cenário
- Crie um diretório:
scenarios/<category>/<name>/. - Crie
scenario.jsoncom os metadados e as expectativas do cenário. - Defina os três estados do banco de dados na configuração JSON: dados base, alterações de ours e alterações de theirs.
- Execute o cenário:
./bin/test-scenario <name>. - 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.