tengo lo siguiente clase de prueba de unidad abstracta que todas mis clases de pruebas unitarias concretas se extienden:
@ExtendWith(SpringExtension.class)
//@ExtendWith(MockitoExtension.class)
@SpringBootTest(
classes = PokerApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
public abstract class AbstractUnitTests {
@MockBean
public RoundService roundService;
@MockBean
public RoundRepository roundRepository;
}
¿Cuál es la diferencia entre usar @ExtendWith(SpringExtension.class)
o @ExtendWith(MockitoExtension.class)
?
Pregunto porque usar cualquiera de las anotaciones parece no hacer ninguna diferencia y ambas funcionan respectivamente en mi código, lo que me permite usar Junit5. Entonces, ¿por qué ambos funcionan?
Clase de ensayo de hormigón:
@DisplayName("Test RoundService")
public class RoundsServiceTest extends AbstractUnitTests {
private static String STUB_USER_ID = "user3";
// class under test
@InjectMocks
RoundService roundService;
private Round round;
private ObjectId objectId;
@BeforeEach //note this replaces the junit 4 @Before
public void setUp() {
initMocks(this);
round = Mocks.round();
objectId = Mocks.objectId();
}
@DisplayName("Test RoundService.getAllRoundsByUserId()")
@Test
public void shouldGetRoundsByUserId() {
// setup
given(roundRepository.findByUserId(anyString())).willReturn(Collections.singletonList(round));
// call method under test
List<Round> rounds = roundService.getRoundsByUserId(STUB_USER_ID);
// asserts
assertNotNull(rounds);
assertEquals(1, rounds.size());
assertEquals("user3", rounds.get(0).userId());
}
}
Sección relevante de Build.gradle :
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.2.RELEASE'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
implementation 'junit:junit:4.12'
}
test {
useJUnitPlatform()
}
RG
¿Qué es una Extensión Junit?
El propósito de las extensiones de Junit 5 es extender el comportamiento de las clases o métodos de prueba.
Sigue leyendo Modelo de extensión Junit 5 & @ExtendWith
anotación:aquí
SpringExtension integra Spring TestContext Framework en el modelo de programación Júpiter de JUnit 5.
public class SpringExtension
extends Object
implements BeforeAllCallback, AfterAllCallback, TestInstancePostProcessor, BeforeEachCallback, AfterEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver{..}
Esta extensión es el equivalente JUnit Júpiter de nuestro JUnit4 MockitoJUnitRunner
public class MockitoExtension
extends java.lang.Object
implements BeforeEachCallback, AfterEachCallback, ParameterResolver{..}
Como se puede ver, SpringExtension
implementa muchas más extensiones que MockitoExtension
.
También @SpringBootTest
está meta anotado con @ExtendWith(SpringExtension.class)
y lo que significa que cada vez que sus pruebas se amplían con SpringExtension
.
@MockBean
es una anotación del marco de prueba de Spring y se usa junto con @ExtendWith(SpringExtension.class)
Para observar la diferencia prueba lo siguiente
ExtendWith
solo MockitoExtension
@ExtendWith(MockitoExtension.class)
class TestServiceTest {
@MockBean
TestService service;
@Test
void test() {
assertNotNull(service); // Test will fail
}
}
ExtendWith
solo SpringExtension
@ExtendWith(SpringExtension.class)
class TestServiceTest {
@MockBean
TestService service;
@Test
void test() {
assertNotNull(service); // Test succeeds
}
}
ExtendWith
con ambos SpringExtension
y MockitoExtension
@ExtendWith(MockitoExtension.class)
@ExtendWith(SpringExtension.class)
class TestServiceTest {
@MockBean
TestService service;
@Test
void test() {
assertNotNull(service); // Test succeeds
}
}
Ambos funcionan en su caso debido a la @SpringBootTest
anotación para la clase de prueba como se explica.
Para responder a la pregunta: Cuándo usar @ExtendWith
¿Primavera o Mockito? ,
Cuando la prueba requiere un contexto de prueba de primavera (para autoconectar un bean/uso de @MockBean
) junto con el uso del modelo de programación Júpiter de JUnit 5 @ExtendWith(SpringExtension.class)
. Esto también admitirá las anotaciones de Mockito a través de TestExecutionListeners.
Cuando la prueba usa Mockito y necesita el uso de soporte del modelo de programación Júpiter de JUnit 5 @ExtendWith(MockitoExtension.class)
Espero que esto ayude
-
¿Debería el uso de
@InjectMocks
trabajar en este contexto con Junit5? Lo intenté y obtuve un error extraño.– djangofan
2 de marzo de 2021 a las 17:58
-
@djangofan publica una pregunta SO con un caso de prueba reproducible
– RG
3 de marzo de 2021 a las 2:36
-
Cuándo usar
@ExtendWith(SpringExtension.class)
o@SpringBootTest
?– LunaticJape
23 de julio de 2021 a las 19:26
-
¿Podemos usar una maqueta en @ExtendWith(SpringExtension.class)?
– NIRAJ KUMAR
20 de enero de 2022 a las 9:33
-
Alguna vez lees algo y piensas hombre, desearía que escribieran los documentos así.
– nerdista
14 de febrero de 2022 a las 13:59
Cuando usar @ExtendWith(SpringExtension.class) o @SpringBootTest?
-
Cuando usa la prueba de integración -anotación @SpringBootTest- o cualquier prueba de división -anotaciones @xxxTest- no necesita la anotación @ExtendWith(SpringExtension.class) ya que las anotaciones mencionadas la incluyen.
-
Si prueba @ConfigurationProperties, @Service, @Component clase anotada (no definida en los casos de prueba de segmento – ref: Spring Boot Reference Document Testing/Auto-configure/SLICED Tests item-, puede usar @ExtendWith(SpringExtension.class) en lugar de @SpringBootTest.
Observación: Espero que una prueba con @ExtendWith(SpringExtension.class) sea más rápida que la misma prueba con @SpringBootTest. Cuando realizo una prueba en Eclipse observé lo contrario.
-
En nuestro caso, usamos @SpringBootTest y pasamos las clases de configuración específicas necesarias para la prueba. Si, en cambio, usamos solo @ExtendWith(SpringExtension.class), construye todo el contexto de la aplicación, lo que por supuesto lleva más tiempo.
– Kyrstellaine
15 de diciembre de 2021 a las 22:07
Excálibur
Para agregar información adicional: también descubrí recientemente que si usa @Mock
dependencias anotadas en la clase de prueba con MockitoExtension
y tratas de usar Mockito.when(mockedDependency.methodName())
en @BeforeAll
método de configuración, entonces obtendrá un NullPointer
en tu dependencia burlada.
pero si cambias MockitoExtension
a SpringExtension
, funciona bien. parece con SpringExtension
los frijoles simulados se inicializan antes (antes JUnit
lanzamientos @BeforeAll
método) tal como debería funcionar correctamente.