Cobertura de código con test funcionales para superhéroes

47
Cobertura de código con test funcionales para superhéroes de hoy en día Víctor Madrid Triviño

Transcript of Cobertura de código con test funcionales para superhéroes

Page 1: Cobertura de código con test funcionales para superhéroes

Cobertura de código con test funcionales para superhéroes de

hoy en día

Víctor Madrid Triviño

Page 2: Cobertura de código con test funcionales para superhéroes

Agradecimientos

Page 3: Cobertura de código con test funcionales para superhéroes

¿Quién soy yo?

Page 4: Cobertura de código con test funcionales para superhéroes

Índice :• Introducción• Conceptos• Demo• Conclusiones

Page 5: Cobertura de código con test funcionales para superhéroes

Introducción

Page 6: Cobertura de código con test funcionales para superhéroes

Zona de confort …

Page 7: Cobertura de código con test funcionales para superhéroes

Zona de trabajo …

Page 8: Cobertura de código con test funcionales para superhéroes

Pregunta :

Page 9: Cobertura de código con test funcionales para superhéroes

Golpe de realidad

Page 10: Cobertura de código con test funcionales para superhéroes

Conceptos

Page 11: Cobertura de código con test funcionales para superhéroes

Teoría de la Ventana Rota

Page 12: Cobertura de código con test funcionales para superhéroes

Problema del Billón de Dólares

Page 13: Cobertura de código con test funcionales para superhéroes

Mala Cultura• XXX

Page 14: Cobertura de código con test funcionales para superhéroes

Desarrollo vs. Testing• XXX

Page 15: Cobertura de código con test funcionales para superhéroes

Automatización• XXX

Page 16: Cobertura de código con test funcionales para superhéroes

Pruebas Unitarias• Prueba la funcionalidad del código• Realizado por los desarrolladores• No pueden acceder a los recursos externos (no

acceden a la red, ni BD, etc.)• Asociados al perfil de desarrollo

“development”• Automatización• Muy mala práctica no realizarlos• Enfoque “caja blanca”• Pieza clave en la metodología TDD

Page 17: Cobertura de código con test funcionales para superhéroes

Pruebas de Integración• Pruebas relacionadas con el acceso a datos o con el uso de

otros componentes -> Relación con otras partes• Realizado por los desarrolladores• Asociados al perfil de desarrollo “integration”• Automatización• Muy mala práctica no realizarlos• Enfoque “caja blanca”• Requieren configuración

• Por ejemplo : Spring• Técnicas :

Top down Bottom up Big bang etc.

Page 18: Cobertura de código con test funcionales para superhéroes

Pruebas Funcionales• Pruebas relacionadas con el funcionamiento del

sistema, comprueba que se cumplan las funciones específicas para las cuales han sido desarrollado

• Realizado por los analistas funcionales y clientes• Enfoque “caja negra”• Automatización• El nivel de conocimiento de negocio del tester

tiene que ser similar al del cliente

Page 19: Cobertura de código con test funcionales para superhéroes

Cobertura

Page 20: Cobertura de código con test funcionales para superhéroes

Proyecto “envenenado”

Page 21: Cobertura de código con test funcionales para superhéroes

Equipos multidisciplinares

Page 22: Cobertura de código con test funcionales para superhéroes

Resolver el problema …

Page 23: Cobertura de código con test funcionales para superhéroes

El elegido …

Page 24: Cobertura de código con test funcionales para superhéroes

Miedito …

Page 25: Cobertura de código con test funcionales para superhéroes

El perfil adecuado …

Page 26: Cobertura de código con test funcionales para superhéroes

Demo

Page 27: Cobertura de código con test funcionales para superhéroes

Contexto• Nuestro jefe : Bruce Wayne / Batman• NO se puede desvelar ninguna identidad• Existe una empresa : WAYNE ENTERPRISE

– Filial : WAYNE Consulting • Cualquier desarrollo lo tiene que implementar en su

mayoría un proveedor externo– No hay tiempo/dinero/recursos para realizar un desarrollo propio

entero, pero sí para realizar adaptaciones del código– Ocultar al máximo el objetivo final : Por ejemplo solicitar un CRUD de

Funcionarios

Page 28: Cobertura de código con test funcionales para superhéroes

Organización• Batman tiene una organización global : Batman

Inc. • Sistema de Franquicias • Problema : Cada país tiene su propias leyes• Proyectos / librerías de arquitectura de Batman :

– bat-architecture-testing– bat-architecture-common

Page 29: Cobertura de código con test funcionales para superhéroes

Somos…Batman Madrid• Nos regimos por las leyes Europeas y de España• Regla básica : “NO matamos pero SÍ se

detiene”• Problema : En España NO dominamos mucho el

inglés

Page 30: Cobertura de código con test funcionales para superhéroes

Necesidad• Batman Madrid necesita una nueva aplicación

web para la gestión de villanos, gestión de recursos , imputación de horas, etc. – bat-desk

Page 31: Cobertura de código con test funcionales para superhéroes

“Requerimientos”• NO puede existir documentación o

referencias a metodologías de desarrollo / funcionalidad / testing / QA

• Utilización de una Arquitectura Open Source basada en Java con tecnologías actuales

• Uso de buenas prácticas de desarrollo• A realizar en : “2 semanas como máximo”

– Porque seguro que son 2 “if-then-else” y 4 pantallitas

Page 32: Cobertura de código con test funcionales para superhéroes

Tecnologías Desarrollo• Arquitectura basada en tecnología : Java

• Herramienta de construcción automática : Maven

• Trazas de la aplicación : Logback

• Framework de Spring y Spring MVC

• Spring Boot

• Persistencia de datos : Mybatis

• Servidores Embebidos (servidor ligero embebido) : Tomcat

• Bases de datos Embebidas (BD que se crea y se utiliza en memoria) : H2

Page 33: Cobertura de código con test funcionales para superhéroes

Tecnologías Testing• Frameworks de test unitarios y de integración : JUnit

• Mocking (creación de objetos simulados) : Mockito

• Framework de matchers (facilita comprobaciones) : Hamcrest

• Frameworks de test funcionales : Selenium

• Navegador (navegador sin interfaz grafica basado en Webkit): Phantom.js• WebDriver para PhantomJS, : Ghost Driver

• Wrapper de Selenium : Fluentlenium

• Cobertura del código : Porcentaje de código accedido por test : CoberturaCobertura

Page 34: Cobertura de código con test funcionales para superhéroes

Ayuda Extra• Somos muy amigos de “Batman Londres” y

nos ha facilitado el módulo de villanos que casi tiene implementado porque es muy parecido a lo que nosotros necesitamos– bat-villain-core

Opciones : Caso 1 : Uso Librería de Terceros Caso 2 : Integración total en el desarrollo Caso 3 : Módulo externo en el desarrollo

Page 35: Cobertura de código con test funcionales para superhéroes

Estructura de Proyectosbat-architecture-testingbat-architecture-commons

bat-desk

bat-desk-common

bat-desk-web

bat-villain-core

Page 36: Cobertura de código con test funcionales para superhéroes

Estados :• Libre (FREE)• Detenido(DETAINED)• Muerto(DEAD)

Servicio de “Detención”@Service("villainOperationService")public class VillainOperationServiceImpl implements VillainOperationService {

…@Overridepublic void detain(long villainId) throws BatDeskException {

LOG.trace("Detaining Villain with id : {}", villainId);

final Villain villain = villainMapper.findByPK(villainId);

generateNotFoundException(villain);

if (VillainValidation.INSTANCE.isDead(villain)){throw new BatDeskException(VillainTypeExceptionEnum.IS_DEAD.name());

}

if (VillainValidation.INSTANCE.isDetained(villain)){throw new BatDeskException(VillainTypeExceptionEnum.IS_DETAINED.name());

}

villain.setStatus(VillainStatusEnum.DETAINED);

if (villainMapper.update(villain) == 0) {throw new BatDeskException(VillainTypeExceptionEnum.DB_ERROR.name());

}

LOG.trace("Villain detained with id : {}", villainId);}…

}

Importante :Este servicio se encuentra en el módulo : bat-villain-core

Page 37: Cobertura de código con test funcionales para superhéroes

Test : Servicio de “Detención”public class VillainOperationServiceTest {

private VillainOperationServiceImpl villainOperationService;private VillainMapper villainMapper;private Villain villainTest;

@Beforepublic void initTests() {

...}

@Test (expected=BatDeskException.class)public void shouldDetainNotFoundException() throws BatDeskException {

when(villainMapper.findByPK(anyLong())).thenReturn(null);

villainOperationService.detain(VillainConstant.TEST_ID);}

@Test (expected=BatDeskException.class)public void shouldDetainWithDeadStatusException() throws BatDeskException {

villainTest.setStatus(VillainStatusEnum.DEAD);

villainOperationService.detain(VillainConstant.TEST_ID);}

@Testpublic void shouldDetain() throws BatDeskException {

villainTest.setStatus(VillainStatusEnum.FREE);when(villainMapper.update(villainTest)).thenReturn(1);

villainOperationService.detain(VillainConstant.TEST_ID);

assertEquals(VillainStatusEnum.DETAINED,villainTest.getStatus());}

}

Page 38: Cobertura de código con test funcionales para superhéroes

Controlador de “Detención”@Controller("villainController")@RequestMapping(value = "/villain/*")public class VillainController {

...@RequestMapping(value = "/detain", method = RequestMethod.GET)public ModelAndView detain(@RequestParam("id") Long villainId, HttpServletRequest request, final RedirectAttributes redirectAttributes) {

LOG.info("Detaining Villain with id : {}", villainId);ModelAndView modelAndView = new ModelAndView(ViewConstant.REDIRECT_LIST_REQUEST_MAPPING);

Villain villainFound = villainService.findByPK(villainId);

if (!VillainValidation.INSTANCE.isValid(villainFound)) {final String error = messageSource.getMessage("villain.validation.error.NOT_FOUND", new Object[] { villainId },

RequestContextUtils.getLocale(request) );modelAndView.addObject(ParameterConstant.PARAM_EXCEPTION, error);modelAndView.setViewName(ViewConstant.ERROR_VIEW);

} else {

try {villainOperationService.detain(villainId);final String success = messageSource.getMessage("villain.validation.IS_DETAINED", new Object[]

{ villainId }, RequestContextUtils.getLocale(request) );redirectAttributes.addFlashAttribute(ParameterConstant.PARAM_MESSAGE, success);LOG.info("Villain with id {} is detained", villainId);

} catch (BatDeskException e) {LOG.error("BatDeskException : Villain with id {} not detained by '{}'", villainId, e.getMessage());final String error = messageSource.getMessage("villain.validation.error."+e.getMessage(), new

Object[] { villainId }, RequestContextUtils.getLocale(request) );redirectAttributes.addFlashAttribute(ParameterConstant.PARAM_EXCEPTION, error );

}}

return modelAndView;}...

}Importante :Este servicio se encuentra en el módulo : bat-desk-web

Page 39: Cobertura de código con test funcionales para superhéroes

Test : Controlador de “Detención”public class VillainControllerTest {

private final String MESSAGE_SOURCE_VALUE = "TEST";private VillainController villainController;private VillainService villainService;private VillainOperationService villainOperationService;private RedirectAttributes redirectAttributes;...@Beforepublic final void setUp() throws Exception {

…villainController = spy(new VillainController());villainService = mock(VillainService.class);villainOperationService = mock(VillainOperationService.class);…when(messageSource.getMessage(anyString(), any(Object[].class), anyObject())).thenReturn(MESSAGE_SOURCE_VALUE);when(villainService.findByPK(anyLong())).thenReturn(villainTest);

}

@Testpublic final void shouldBeDetainNoFound() {

when(villainService.findByPK(anyLong())).thenReturn(null);final ModelAndView modelAndView = villainController.detain(VillainConstant.TEST_ID, request, redirectAttributes);final String message = (String) modelAndView.getModel().get(ParameterConstant.PARAM_EXCEPTION);assertEquals(ViewConstant.ERROR_VIEW,modelAndView.getViewName());assertEquals(MESSAGE_SOURCE_VALUE,message);

}

@Testpublic final void shouldBeDetain() throws BatDeskException {

final ModelAndView modelAndView = villainController.detain(VillainConstant.TEST_ID, request, redirectAttributes);

assertEquals(ViewConstant.REDIRECT_LIST_REQUEST_MAPPING,modelAndView.getViewName());}

}

Page 40: Cobertura de código con test funcionales para superhéroes

Test Funcional de “Detención”@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(classes = SpringBootWebApplication.class)@WebAppConfiguration@IntegrationTest("server.port:8080")public class DetainSeleniumIT extends FluentTest {

private final String NAVIGATION_VILLAIN_LIST = "navigation_villain_list";@Value("${local.server.port}")private int serverPort;private WebDriver webDriver = new PhantomJSDriver();

@Testpublic void testBatDeskPage_Dead() { goTo(getUrl()); // Villain List find(By.id(NAVIGATION_VILLAIN_LIST)).click(); // Detain Dead Villain find(By.id("detain_4")).click(); find(By.id("notificationException"));}

@Testpublic void testBatDeskPage_Free() { goTo(getUrl()); // Villain List find(By.id(NAVIGATION_VILLAIN_LIST)).click(); // Detain Free Villain find(By.id("detain_1")).click(); find(By.id("notificationMessage"));}

}

Page 41: Cobertura de código con test funcionales para superhéroes

Despliege Bat-Desk• Arranque con Spring Boot• Despliegue automático en Tomcat Embebido

Page 42: Cobertura de código con test funcionales para superhéroes

Reporting “Cobertura”• Informe de cobertura de código integrado en el

“site”• Opcional : Ejecución con diferentes perfiles

Page 43: Cobertura de código con test funcionales para superhéroes

Conclusiones

Page 44: Cobertura de código con test funcionales para superhéroes

Calidad de vida

Page 45: Cobertura de código con test funcionales para superhéroes

Trabajar con principios

Page 46: Cobertura de código con test funcionales para superhéroes

Yo soy ….QAtman !!!

Page 47: Cobertura de código con test funcionales para superhéroes

Dudas