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

Upload: atsistemas

Post on 15-Apr-2017

358 views

Category:

Software


0 download

TRANSCRIPT

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