2. Compilar y probar .NET y Java
Secciones
Ajustes de lectura
Voz natural grabada para este curso, la misma en todos los navegadores.
Ninguna voz para este idioma en este navegador.
Más voces
Código y términos técnicos en inglés
Desactivado: la voz de la página lo lee todo, sin pausa entre dos voces.
Ninguna voz para este idioma en este navegador.
Más voces
Más voces: Microsoft Edge ofrece voces naturales en línea, y Windows (Configuración › Hora e idioma › Voz), macOS y Android instalan otras.
El proyecto
Sección titulada «El proyecto»code/github-actions contiene dos veces la misma pequeña función — convertir un título en un slug de URL — con cuatro pruebas en cada lado:
| .NET | Java | |
|---|---|---|
| Código | dotnet/Slugs/Slug.cs |
java/src/main/java/com/example/slugs/Slug.java |
| Pruebas | xUnit v3 [Theory] + [InlineData] |
JUnit 6 @ParameterizedTest + @CsvSource |
| Comando | dotnet test |
mvn -B verify |
| SDK fijado por | global.json |
maven.compiler.release en pom.xml |
De dotnet/Slugs.Tests/SlugTests.cs, líneas 8-14:
[Theory][InlineData("Hello, Wörld!", "hello-world")][InlineData(" GitHub Actions ", "github-actions")][InlineData("C# 14 & .NET 10", "c-14-net-10")][InlineData("", "")]public void From_builds_a_lowercase_ascii_slug(string text, string expected) => Assert.Equal(expected, Slug.From(text));Antes de escribir YAML: tiene que pasar en local, con los mismos comandos que ejecutará la CI. Ahí aparecieron las dos primeras trampas de esta lección.
Trampa 1: xUnit v3 y dotnet test con el SDK de .NET 10
Sección titulada «Trampa 1: xUnit v3 y dotnet test con el SDK de .NET 10»Con xunit.v3 4.0.1, el primer dotnet test falló antes de ejecutar nada:
error : Testing with VSTest target is no longer supported by Microsoft.Testing.Platform on .NET 10 SDK and later. If you use dotnet test, you should opt-in to the new dotnet test experience. For more information, see https://aka.ms/dotnet-test-mtp-errorxUnit v3 se ejecuta sobre Microsoft.Testing.Platform, y el SDK de .NET 10 quiere que actives explícitamente el nuevo dotnet test, en global.json (dotnet/global.json):
{ "sdk": { "version": "10.0.100", "rollForward": "latestFeature" }, "test": { "runner": "Microsoft.Testing.Platform" }}Trampa 2: no hay using Xunit implícito
Sección titulada «Trampa 2: no hay using Xunit implícito»Siguiente error:
CS0246: The type or namespace name 'Theory' could not be found (are you missing a using directive or an assembly reference?)CS0246: The type or namespace name 'InlineData' could not be found (are you missing a using directive or an assembly reference?)Con ImplicitUsings activado, este paquete 4.0.1 no añadía Xunit a los usings globales: el archivo de pruebas necesita using Xunit;. Después:
Test run summary: Passed! total: 4 failed: 0 succeeded: 4 skipped: 0El workflow
Sección titulada «El workflow».github/workflows/gha-02-build.yml:
# GitHub Actions course, lesson 2: build and test .NET and Java on three OSesname: "GHA 02: build and test"
on: workflow_dispatch: push: branches: [main] paths: ['code/github-actions/**', '.github/workflows/gha-02-build.yml'] pull_request: paths: ['code/github-actions/**', '.github/workflows/gha-02-build.yml']
jobs: dotnet: name: dotnet (${{ matrix.os }}) strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} defaults: run: working-directory: code/github-actions/dotnet steps: - uses: actions/checkout@v7 - uses: actions/setup-dotnet@v6 with: global-json-file: code/github-actions/dotnet/global.json - run: dotnet --version - run: dotnet test
java: name: java (${{ matrix.os }}) strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} defaults: run: working-directory: code/github-actions/java steps: - uses: actions/checkout@v7 - uses: actions/setup-java@v6 with: distribution: temurin java-version: '25' cache: maven - run: java --version - run: mvn -B verify| Elemento | Efecto |
|---|---|
strategy.matrix.os |
un job por valor: 3 jobs dotnet y 3 jobs java, todos en paralelo |
fail-fast: false |
un fallo en Windows no cancela el job de macOS que sigue en curso (el valor por defecto, true, sí lo hace) |
name: dotnet (${{ matrix.os }}) |
el nombre del job que se muestra en la ejecución; sin name, GitHub usa el id del job y todos los valores de la matrix, p. ej. java (ubuntu-latest, 22) |
defaults.run.working-directory |
cada run: empieza en esa carpeta (los steps uses: no se ven afectados) |
actions/setup-dotnet con global-json-file |
instala el SDK que pide global.json |
actions/setup-java con cache: maven |
instala Temurin 25 y guarda ~/.m2/repository en caché, con una clave basada en el hash de pom.xml |
mvn -B |
modo batch: sin colores ni barras de progreso de descarga en el log |
Lo que muestra la ejecución
Sección titulada «Lo que muestra la ejecución»Los seis jobs pasaron. Extractos:
dotnet (ubuntu-latest) | dotnet-install: Installed version is 10.0.401dotnet (ubuntu-latest) | 10.0.401java (ubuntu-latest) | Resolved Java 25.0.4+1 from tool-cachejava (ubuntu-latest) | openjdk 25.0.4.1 2026-08-18 LTSjava (ubuntu-latest) | [INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0java (ubuntu-latest) | [INFO] BUILD SUCCESSglobal.jsonindica10.0.100conrollForward: latestFeature:setup-dotnetinstaló la última banda de características de 10.0, 10.0.401. Fija"rollForward": "disable"si necesitas exactamente un SDK.- Temurin 25 ya estaba en la imagen de Ubuntu (
from tool-cache): sin descarga.
El shell no es el mismo en todas partes. El mismo step run: dotnet test registró:
dotnet (ubuntu-latest) | shell: /usr/bin/bash -e {0}dotnet (macos-latest) | shell: /bin/bash -e {0}dotnet (windows-latest) | shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'"En Windows, run: usa PowerShell 7 por defecto. dotnet test y mvn -B verify se comportan igual en ambos, pero un script con $(pwd), export o cadenas con && no. Define defaults.run.shell: bash para el job (Git Bash está instalado en los runners de Windows) cuando un script deba ser idéntico en los tres sistemas operativos.
La caché, medida
Sección titulada «La caché, medida»La primera ejecución no encontró caché de Maven y guardó una; una segunda ejecución (iniciada con gh workflow run gha-02-build.yml) la restauró (setup-java/src/cache.ts):
maven cache is not foundCache saved with the key: setup-java-Linux-x64-maven-4b450ab7781caaed20d3b55ef20c4500aaacb6aad3f54b145929988a7515a1ebCache restored from key: setup-java-Linux-x64-maven-4b450ab7781caaed20d3b55ef20c4500aaacb6aad3f54b145929988a7515a1ebCache hit occurred on the primary key setup-java-Linux-x64-maven-4b450ab7781caaed20d3b55ef20c4500aaacb6aad3f54b145929988a7515a1eb, not saving cache.| Job | 1.ª ejecución (sin caché) | 2.ª ejecución (acierto de caché) |
|---|---|---|
| java (ubuntu-latest) | 16 s | 10 s |
| java (windows-latest) | 43 s | 28 s |
| java (macos-latest) | 20 s | 9 s |
| dotnet (ubuntu-latest) | 21 s | 22 s |
| dotnet (windows-latest) | 60 s | 57 s |
| dotnet (macos-latest) | 20 s | 22 s |
Los jobs de .NET no se aceleraron: todavía nada guarda en caché los paquetes NuGet. setup-dotnet tiene una opción cache: true basada en archivos packages.lock.json, medida en la lección 5. La clave contiene el sistema operativo (Linux-x64, Windows-x64, macOS-arm64): cada sistema operativo tiene su propia caché. Y macos-latest es una máquina arm64.
Puntos clave
Sección titulada «Puntos clave»- Primero haz que pase en local, exactamente con los comandos que ejecuta la CI.
- Una
matrixmultiplica un job;fail-fast: falsedeja que cada combinación termine. setup-dotnetleeglobal.json;setup-javainstala un JDK y guarda Maven o Gradle en caché.run:es bash en Linux/macOS y PowerShell 7 en Windows, salvo que definasshell.- Mide: aquí un acierto de la caché de Maven ahorró de 6 a 15 segundos por job; los jobs de Windows son los más lentos.
Ejercicios
Sección titulada «Ejercicios»- Añade
22junto a25para que el job de Java se ejecute también con Java 22, en los tres sistemas operativos. ¿Cuántos jobs de Java se ejecutarán?
Solución
name: java ${{ matrix.java }} (${{ matrix.os }}) strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] java: ['25', '22'] steps: - uses: actions/setup-java@v6 with: distribution: temurin java-version: ${{ matrix.java }} cache: maven6 jobs (3 × 2). Pero el build falla con 22: pom.xml fija maven.compiler.release en 25. Comprobado con gha-02-exercises.yml:
[INFO] BUILD FAILURE[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.15.0:compile (default-compile) on project slugs: Fatal error compiling: error: release version 25 not supported -> [Help 1]Una matrix prueba combinaciones; el proyecto tiene que soportarlas.
- Quieres que el job de Windows ejecute
dotnet testen bash, como los demás. ¿Dónde ponesshell: bashpara que se aplique a cadarun:del job?
Solución
defaults: run: shell: bash working-directory: code/github-actions/dotnetdefaults.run a nivel de job (o a nivel de workflow para todos los jobs). En Windows el log muestra entonces:
shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}bash 5.3.15(2)-release, options ehBFíjate en -o pipefail: un shell: bash explícito también falla cuando falla un comando en medio de una tubería, cosa que no hace el bash -e {0} implícito de los runners de Linux.
- Sin
using Xunit;, ¿qué error mostraría la CI, y en cuántos jobs?
Solución
CS0246: The type or namespace name 'Theory' could not be found, en los tres jobs dotnet. Con fail-fast: false los tres se ejecutan hasta el final; con el valor por defecto fail-fast: true, el primer fallo cancela los otros jobs dotnet aún en curso — los jobs java vienen de otra definición de job, con su propia matrix, y no se ven afectados.