Las pruebas deben de ser un conjunto EFECTIVO (deben detectar el máximo número posible de errores) y EFICIENTE (con el menor número posible de casos de prueba).
Ubicaciones directorios¶
Para la clase Cosa.java.
project-home/ --> Carpeta raíz que contiene el proyecto Maven
├── src/ --> Ficheros
│ ├── main/
│ │ ├── java/ --> Código fuente en Java
│ │ │ └── paquete/ --> Paquete raíz del proyecto
│ │ │ ├── excepciones/
│ │ │ │ └── CosaException.java --> Manejo de excepciones
│ │ │ └── Cosa.java --> Clase principal
│ │ └── resources/ --> Archivos adicionales usados por el código fuente
│ └── test/ --> Pruebas
│ ├── java/ --> Código fuente de las pruebas en Java
│ │ └── paquete/ --> Paquete raíz de pruebas
│ │ ├── CosaTest.java --> Clase de prueba
│ │ ├── CosaTestable.java --> Clase para la inyección de dependencias
│ │ └── CosaStub.java --> STUB para pruebas
│ └── resources/ --> Archivos adicionales para pruebas
│
├── target/ --> Generado automáticamente por Maven (build)
│ ├── classes/ --> Archivos compilados del código fuente
│ ├── test-classes/ --> Archivos compilados del código de prueba
│ ├── surefire-reports/ --> Reportes de ejecución de pruebas unitarias
│ │ ├── paquete.CosaTest.txt
│ │ └── TEST-paquete.CosaTest.xml
│ ├── failsafe-reports/ --> Reportes de pruebas de integración
│ ├── generated-sources/ --> Código fuente generado automáticamente
│ ├── generated-test-sources/ --> Código de prueba generado automáticamente
│ ├── maven-status/ --> Información del estado de compilación
│ ├── site/ --> Documentación del proyecto generada con `mvn site`
│ ├── dependency/ --> Dependencias copiadas localmente (si se configura)
│ └── [nombre].jar --> Archivo JAR final generado (si aplica)
│
└── pom.xml --> Archivo de configuración del proyecto (POM)
Configuración pom.xml¶

Ejemplo de configuración completa siguiendo el esquema de estructura del pom:
<!-- Coordenadas -->
<groupId>ppss.practica3</groupId>
<artifactId>drivers</artifactd>
<version>1.0-SNAPSHOT</version>
<!-- Variables -->
<properties>
<maven.compiler.source>25</maven.compiler.source>
<maven.compiler.target>25</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- Librerías -->
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Construcción -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>
Dependencias¶
JUnit5¶
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.4</version>
<scope>test</scope>
</dependency>
- Para definir y ejecutar las pruebas.
- Proporciona las anotaciones necesarias para estructurar el código de prueba (
@Test,@BeforeEach,@AfterAll) y los métodos assert (assertEquals(),assertTrue(),assertThrows()).
EasyMock¶
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>5.5.0</version>
<scope>test</scope>
</dependency>
- Para crear los dobles de pruebas.
Plugins¶
Maven Surefire Plugin (para JUnit-5 / tests unitarios)¶
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
<!-- Opcional: incluir/excluir tests -->
<configuration>
<!-- Por defecto ejecuta clases *Test.java, Test*.java y *Tests.java -->
<!-- <includes><include>**/*Test.java</include></includes> -->
<!-- <excludes><exclude>**/IT_*.java</exclude></excludes> -->
</configuration>
</plugin>
- Usos:
- Ejecutar los unit-tests en la fase
test. - Detecta automáticamente tests JUnit 5 (JUnitPlatform).
- Permite filtros
<includes>/<excludes>para naming conventions.
- Ejecutar los unit-tests en la fase
Configuración para drivers
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
<dependencies>
<dependency>
<groupId>me.fabriciorby</groupId>
<artifactId>maven-surefire-junit5-tree-reporter</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
<configuration>
<reportFormat>plain</reportFormat>
<consoleOutputReporter>
<disable>true</disable>
</consoleOutputReporter>
<statelessTestsetInfoReporter implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
<printStacktraceOnError>true</printStacktraceOnError>
<printStacktraceOnFailure>true</printStacktraceOnFailure>
<printStdoutOnError>true</printStdoutOnError>
<printStdoutOnFailure>true</printStdoutOnFailure>
<printStdoutOnSuccess>false</printStdoutOnSuccess>
<printStderrOnError>true</printStderrOnError>
<printStderrOnFailure>true</printStderrOnFailure>
<printStderrOnSuccess>false</printStderrOnSuccess>
</statelessTestsetInfoReporter>
</configuration>
</plugin>
- La dependencia del plugin
maven-surefire-junit5-tree-reportercambia la salida de la consola de Maven como un árbol estructurado y jerárquico.
Maven Compiler Plugin¶
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>21</source>
<target>21</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
- Usos:
- Compilar el código Java de
src/main/java(fasecompile). - Compilar tests de
src/test/java(fasetest-compile). - Ajustar nivel de lenguaje (
source/target) y codificación.
- Compilar el código Java de
Dependencias¶
Stubs¶
S05.1 - Flujo de dependencias y ficheros en STUBs
Mocks¶
- Estructura habitual de los tests con
EasyMock:
VARIABLES
private IMocksControl control;
private FicheroTexto sut;
private FileReader fileReaderMock;
SETUP
- Para inicializar las variables, crear los dobles e inicializar la sut.
@BeforeEach
public void setUp() {
control = EasyMock.createStrictControl();
// doble total
fileReaderMock = control.createMock(FileReader.class);
// mock parcial de la sut para el metodo getFileReader
sut = EasyMock.partialMockBuilder(FicheroTexto.class)
.addMockedMethod("getFileReader")
.mock(control);
}
TEST
Los tests con EasyMock siguen un ciclo de vida de 4 pasos:
- Fase RECORD: Todo lo que hagamos con
EasyMock.expect(...). Se prepara el escenario y le decimos a los dobles como deben comportarse y que llamadas deben esperar. - Fase REPLAY: Al llamar a
control.replay(). Esto le dice a EasyMock que ya tienen todas las instrucciones y puede prepararse para ejecutar la sut. - Fase ACT (Ejecutar la SUT): se llama al método de la sut (
sut.contarCaracteres(fichero1)). Al ejecutarse, la SUT hará las llamadas y los mocks responderán con lo que se les enseña en la fase 1. Si la SUT hace algo no programado, EasyMock lanza un error. - Fase VERIFY: Se verifican los resultados reales, con los
assertEqualsoassertThrowsy se llama acontrol.verify()para conformar la interacción de la SUT con los dobles según las veces y el orden especificado.
@Test
public void C1_test1() {
// ===============
// FASE 1: RECORD
// ===============
// para devolver el doble cuando se llame desde la sut
assertDoesNotThrow(() -> {
EasyMock.expect(sut.getFileReader(fichero1))
.andReturn(fileReaderMock);
});
// instrucciones al doble sobre lo que debe devolver a la sut en su ejecución
assertDoesNotThrow(() -> {
EasyMock.expect(fileReaderMock.read())
.andReturn((int) 'a')
.andReturn((int) 'b')
.andThrow(new IOException());
});
// ===============
// FASE 2: REPLAY
// ===============
control.replay();
// ===============
// FASE 3: ACT
// ===============
FicheroException ex = assertThrows(FicheroException.class, () -> sut.contarCaracteres(fichero1));
assertEquals(fichero1 + " (Error al leer el archivo)", ex.getMessage());
// ===============
// FASE 4: VERIFY
// ===============
control.verify();
}
Ejemplo completo¶
package ppss.P06;
// imports
import static org.junit.jupiter.api.Assertions.*;
class FicheroTextoTest {
private String fichero1 = "src/test/resources/fichero1.txt";
private String fichero2 = "src/test/resources/fichero2.txt";
// Se instancian las variables de la sut, dobles/deps y el StrictControl
private IMocksControl control;
private FicheroTexto sut;
private FileReader fileReaderMock;
@BeforeEach
public void setUp() {
control = EasyMock.createStrictControl();
fileReaderMock = control.createMock(FileReader.class);
sut = EasyMock.partialMockBuilder(FicheroTexto.class)
.addMockedMethod("getFileReader")
.mock(control);
}
@Test
public void C1_test1() {
assertDoesNotThrow(() -> {
EasyMock.expect(sut.getFileReader(fichero1))
.andReturn(fileReaderMock);
});
assertDoesNotThrow(() -> {
EasyMock.expect(fileReaderMock.read())
.andReturn((int) 'a')
.andReturn((int) 'b')
.andThrow(new IOException());
});
control.replay();
FicheroException ex = assertThrows(FicheroException.class, () -> sut.contarCaracteres(fichero1));
assertEquals(fichero1 + " (Error al leer el archivo)", ex.getMessage());
control.verify();
}
@Test
public void C2_test2() {
assertDoesNotThrow(() -> {
EasyMock.expect(sut.getFileReader(fichero2)).andReturn(fileReaderMock);
});
assertDoesNotThrow(() -> {
EasyMock.expect(fileReaderMock.read())
.andReturn((int) 'a')
.andReturn((int) 'b')
.andReturn((int) 'c')
.andReturn(-1);
fileReaderMock.close();
EasyMock.expectLastCall().andThrow(new IOException());
});
control.replay();
FicheroException ex = assertThrows(FicheroException.class, () -> sut.contarCaracteres(fichero2));
assertEquals(fichero2 + " (Error al cerrar el archivo)", ex.getMessage());
control.verify();
}
}