Una ejecución real
Un cambio real en Spectre.Console (commit 01027ef), del mapa de cobertura al job summary. Toda la salida de esta página está copiada de esa ejecución, no escrita a mano.
El cambio
Una refactorización de una línea en el widget Rule. No cambia ningún comportamiento, pero es un cambio de código, así que un pipeline normal ejecutaría las 787 pruebas de 141 clases en cada framework de destino.
// src/Spectre.Console/Widgets/Rule.cs, GetLineWithoutTitle
var text = border.GetPart(BoxBorderPart.Top).Repeat(maxWidth);
+var style = Style ?? Spectre.Console.Style.Plain;
return
[
- new Segment(text, Style ?? Spectre.Console.Style.Plain),
+ new Segment(text, style),
Segment.LineBreak
];
La ejecución
El mapa se registró en main con td record. Después, la pull request ejecuta:
$ td test --base main -- -f net10.0td: 1 changed file(s), 1 affected test project(s).Tests to run: filtered src/Spectre.Console.Tests/Spectre.Console.Tests.csproj (14 of 141 test class(es) run or reference the changed code, 0.6 s of 3.0 s (80% saved))Recorded test time: 0.6 s of 3.4 s (83% saved).Passed! - Failed: 0, Passed: 156, Skipped: 0, Total: 156 - Spectre.Console.Tests.dll (net10.0)td summary: passed src/Spectre.Console.Tests/Spectre.Console.Tests.csproj (14 class(es), 4.6 s)1 project(s) run, 0 failed, 0 skipped.Recorded test time: 0.6 s of 3.4 s (83% saved).
Se ejecutaron 156 pruebas de 14 clases en lugar de 787 de 141. El proyecto Spectre.Console.Ansi.Tests ni siquiera se compiló: no cambió nada de lo que depende.
¿Eran esas las 14 correctas?
Para comprobarlo, hicimos que GetLineWithoutTitle lanzara una excepción y ejecutamos el conjunto completo de pruebas. Fallaron exactamente 14 clases, y son las 14 que TestDetta seleccionó: AlignTests+Center, +Left, +Right, CanvasTests, ColumnsTests, ExceptionTests, LayoutTests, PadderTests, PanelTests, RecorderTests, RowsTests, RuleTests, TableTests y TextPathTests. La mayoría nunca menciona Rule: llegan a él a través de layouts y paneles, que es lo que conoce el mapa de cobertura y no encontraría una búsqueda por nombre.
El job summary
Con --summary-file "$GITHUB_STEP_SUMMARY" (la GitHub Action lo define por ti), cada pull request recibe este resumen: qué se ejecutó, por qué se ejecutó cada clase y qué se omitió.
TestDetta test selection
1 changed file(s) compared with main.
- 1 of 1 affected test project(s) ran, 0 skipped.
- Recorded test time: 0.6 s of 3.4 s (83% saved).
- All selected tests passed.
src/Spectre.Console.Tests/Spectre.Console.Tests.csproj: passed, 14 test class(es), recorded time 0.6 s of 3.0 s (80% saved)- why:
14 of 141 test class(es) run or reference the changed code - classes:
AlignTests+Center:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)AlignTests+Left:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)AlignTests+Right:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)CanvasTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)ColumnsTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)ExceptionTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)LayoutTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)PadderTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)PanelTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)RecorderTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)RowsTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)RuleTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)TableTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)TextPathTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)
- skipped: 127 class(es) that ran none of the changed code and name none of it
- why:
Aquí los nombres de clase están abreviados; el resumen los muestra completos (Spectre.Console.Tests.Unit.RuleTests).
Preguntar por qué
Cada decisión tiene un motivo que puedes leer. -v escribe el rastro en stderr:
[DBG] CodeChangeDetector: src/Spectre.Console/Widgets/Rule.cs: Modified Spectre.Console.Rule GetLineWithoutTitle(RenderOptions,int)
[DBG] CodeChangeDetector: src/Spectre.Console/Widgets/Rule.cs: 1 changed symbol(s), affects whole project: False
[DBG] TestSelector: Spectre.Console.Rule GetLineWithoutTitle(RenderOptions,int) is affected because it changed
[DBG] TestSelector: Spectre.Console.Rule Render(RenderOptions,int) is affected because GetLineWithoutTitle
[DBG] TestSelector: Spectre.Console.Rule GetLineWithoutTitle(RenderOptions,int): test classes taken from coverage
Y --format json da la decisión de cada clase, con sus evidencias y una estimación de tiempo, para scripts y paneles:
{
"project": "src/Spectre.Console.Tests/Spectre.Console.Tests.csproj",
"mode": "Filtered",
"reason": "14 of 141 test class(es) run or reference the changed code",
"estimate": {
"fullSeconds": 3,
"selectedSeconds": 0.6,
"savedSeconds": 2.4
},
"decisions": [
{
"class": "Spectre.Console.Tests.Unit.AlignTests+Center",
"selected": true,
"kind": "coverage",
"evidence": "ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)"
},
{
"class": "Spectre.Console.Tests.PublicApiTests",
"selected": false,
"kind": "skipped",
"evidence": "ran none of the changed code and names none of it (map 01027efcd6c4)"
},
"…139 more"
]
}
Ejecutar las pruebas a tu manera
td affected --format commands muestra la llamada a dotnet test que haría TestDetta, para que puedas ejecutarla en tu propio script:
dotnet test src/Spectre.Console.Tests/Spectre.Console.Tests.csproj --filter 'FullyQualifiedName~Spectre.Console.Tests.Unit.AlignTests+Center.|FullyQualifiedName~Spectre.Console.Tests.Unit.AlignTests+Left.|FullyQualifiedName~Spectre.Console.Tests.Unit.AlignTests+Right.|FullyQualifiedName~Spectre.Console.Tests.Unit.CanvasTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.ColumnsTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.ExceptionTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.LayoutTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.PadderTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.PanelTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.RecorderTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.RowsTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.RuleTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.TableTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.TextPathTests.'
En 40 repositorios
Un cambio es un solo dato. En el corpus de evaluación se cambian, uno a uno, miembros de 40 bibliotecas de código abierto; para un cambio en un solo miembro, TestDetta ejecutó una mediana del 28 % de las clases de prueba, y una cuarta parte o menos en 18 de los 40 repositorios. Las bibliotecas en las que casi todas las pruebas tocan el núcleo (Scriban, Markdig) ganan poco; el código organizado en capas es el que más gana. Cada clase que falló se comprobó frente a la selección: se pasaron por alto 3 de 2,941 cambios con fallos, y cada una se corrigió.