test starter mockitojunitrunner mock example java unit-testing spring-boot testng mockito

java - starter - La prueba de la unidad TestNG no funciona después de anotar el servicio para probar con @Retention, @Transactional, @ Heredado



spring-boot-starter-test example (4)

¿Puedes intentar usar MockitoJUnitRunner ?

@RunWith(MockitoJUnitRunner.class) @ContextConfiguration(classes = { TestApp.class }) class MyTestClass{ .. }

Estoy probando un servicio comercial con TestNG, pruebas de unidad de mockito en la aplicación de arranque de primavera.

La aplicación es un proyecto de arranque de primavera de varios módulos. Y estoy escribiendo pruebas de unidades para el módulo de negocios.

He agregado las siguientes pruebas relacionadas con dependencias en pom,

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>${testng.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>el-api</artifactId> <version>${javaxel.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.servlet</artifactId> <version>${javax.servlet.version}</version> <scope>test</scope> </dependency>

Mi anotación de envoltura se ve como

@Service @Transactional @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface MyServiceAnnotation{}

Mi TestApp se parece a

@SpringBootApplication public class TestApp{ .... }

Mi servicio comercial parece

@MyServiceAnnotation public class AddressServiceImpl implements AddressService { @Autowire UserDAO userDAO; @Autowire AddressDAO addressDAO; public Address find(int userId) { user = userDAO.findOne(userId); /** if I run following test then I get user NULL. But it should get user object which I have created in data provider **/ if(user == null ) { throw new BadReqExcp("invalid user Id", 101); } address = user.findAddresses(); if(address is empty) { throw new BadReqExcp("add not found", 102);} return address; } }

MyTestClass se parece a

@ContextConfiguration(classes = { TestApp.class }) class MyTestClass{ @Mock UserDAO userDAO; @InjectMocks @Autowire AddressService addressServie; @BeforeMethod public void initMock() { MockitoAnnotations.initMocks(this); } @Test(dataProvider = "getUser", dataProviderclass = UserDP.class) public void shouldThrowExceptionAddressNotFound(int userId, User user) { when(userDAO.findOne(userId)).thenReturn(user); //here dao call should return user but it is returning null try{ addressService.find(userId); } catch(BadReqExcp e){ // Here errro code should be 102 but fount 101 assertEquals(e.getErrorCode(), 102); } } }

Si no utilizo @Target(ElementType.TYPE) , @Retention(RetentionPolicy.RUNTIME) , @Inherited estas anotaciones, entonces mis llamadas simuladas de DAO en la prueba funcionan bien.

Necesito las anotaciones anteriores explícitamente porque si no las uso, entonces

Por ejemplo, si quiero realizar una única tarea que utiliza múltiples servicios comerciales, entonces no ocurrirá en UNA transacción . En otras palabras, si una llamada comercial usa múltiples servicios comerciales, diga ServiceA y ServiceB . La llamada va de serviceA a serviceB . Si se produce una excepción en serviceB , los cambios en la base de datos realizados por serviceA no se revertirán.

Cuando uso las anotaciones anteriores, el ejemplo anterior funciona PERO las llamadas simuladas a DAO en las pruebas junit no funcionan.

¿Tengo dependencias incorrectas en pom?

  1. ¿Por qué esto no está funcionando?
  2. ¿Cuál sería la solución sobre esto?

Código fuente del repositorio de Git , aquí obtendrá un código de muestra. Me está dando un error al compilar.


Creo que ese problema puede deberse al orden de procesamiento de la anotación.

Probablemente pueda intentar establecer el estado interno de su servicio explícitamente en el método before before like like:

@Mock UserDAO userDAO; @Autowire AddressService addressServie; @BeforeMethod public void initMock() { MockitoAnnotations.initMocks(this); // using mockito Whitebox org.mockito.internal.util.reflection.Whitebox.setInternalState(addressServie, "userDAO", userDAO); /* or using spring test method org.springframework.test.util.ReflectionTestUtils.setField(addressServie, "userDAO", userDAO);*/ }

y verificar si aún se produce un error


Elimina todas tus anotaciones. Necesita algo especial para que las transacciones funcionen.

Problema:

La llamada va de serviceA a serviceB. Si se produce una excepción en serviceB, los cambios en la base de datos realizados por serviceA no se revertirán

El administrador de transacciones de Spring proporciona una API independiente de la tecnología que le permite iniciar una nueva transacción llamando al método getTransaction () y administrándolo por

cometer()
Retroceder()

Como PlatformTransactionManager es una unidad abstracta para la gestión de transacciones,

los métodos que solicitó para la administración de transacciones están garantizados por ser independientes de la tecnología.

import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; public class TransactionalJdbcBookShop extends JdbcDaoSupport implements BookShop { @Autowired private PlatformTransactionManager transactionManager;

.....

luego dentro de su método dao puede configurar el método de confirmación y restitución.

public void purchase(String isbn, String username) { TransactionDefinition def = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(def); try { //Your query over here transactionManager.commit(status); } catch (DataAccessException e) { //if the above query fails then transactionManager.rollback(status); throw e; } }

Un transactionmanager se declara en el archivo de configuración XML como un bean normal.

Por ejemplo,

la siguiente configuración de beans declara una instancia de DataSourceTransactionManager.

Requiere que se establezca la propiedad dataSource para que pueda gestionar transacciones para las conexiones realizadas por esta fuente de datos.

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="bookShop" class="com.apress.springrecipes.bookshop.TransactionalJdbcBookShop"> <property name="dataSource" ref="dataSource" /> <property name="transactionManager" ref="transactionManager" /> </bean>

¿Cómo puedo usar los beans autoconfigurados de Spring Boot en archivos de configuración XML?

También puede ir a través de github para implementar bean dentro de su aplicación here

Una vez que tenga una definición de transacción,

Puede solicitar al gerente de transacciones que inicie una nueva transacción con esa definición llamando al método getTransaction ().

A continuación, devolverá un objeto TransactionStatus para realizar un seguimiento del estado de la transacción.

Si todas las declaraciones se ejecutan correctamente, solicite al gerente de transacciones que confirme esta transacción al pasar el estado de la transacción.

Como todas las excepciones lanzadas por la plantilla Spring JDBC son subclases de DataAccessException, le pide al administrador de la transacción que retrotraiga la transacción cuando se detecta este tipo de excepción.

En esta clase, ha declarado la propiedad del administrador de transacciones del tipo general PlatformTransactionManager .

Ahora debe inyectar una implementación apropiada del administrador de transacciones.

Como se trata solo de una única fuente de datos y de acceder a ella con JDBC, debe elegir DataSourceTransactionManager .


Te recomiendo que mantengas las pruebas simples. Puede aprovechar los beneficios DI. Para más detalles, visite la documentación de Spring :

Una de las principales ventajas de la inyección de dependencia es que debe hacer que su código sea más fácil para la prueba unitaria. Simplemente puede instanciar objetos usando el nuevo operador sin siquiera involucrar a Spring. También puede usar objetos simulados en lugar de dependencias reales.

Tu clase de prueba debería verse así.

public class AddressTest { @Mock private UserDAO userDAO; @Mock private AddressDAO addressDAO; @InjectMocks private AddressService addressServie; @BeforeMethod public void initMock() { addressServie = new AddressServiceImpl(); MockitoAnnotations.initMocks(this); } @Test(dataProvider = "getUser", dataProviderClass = UserDP.class) public void shouldThrowExceptionAddressNotFound(int userId, User user) { when(userDAO.findOne(userId)).thenReturn(user); try { addressServie.findAllAddress(userId); } catch (BadRequestException badRequestException) { assertEquals(badRequestException.getErrorCode(), 102); } } }

También debe verificar la lista de direcciones nulas en su implementación. La prueba falla porque la clase de proveedor proporciona la prueba con una instancia de usuario que no tiene la lista de direcciones inicializada.

@Override public List<Address> findAllAddress(int userId) { User user = userDAO.findOne(userId); if (user == null) { throw new BadRequestException("Invalid user id", 101); } List<Address> addresses = user.getAddresses(); if (addresses == null || addresses.isEmpty()) { throw new BadRequestException("Address Not found", 102); } return addresses; }