teste unitário

31
Teste

Upload: distbp

Post on 13-Jul-2015

141 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Teste unitário

Teste

Page 2: Teste unitário

Estilo de desenvolvimento guiado pela criação de testes que validam a funcionalidade implementada antes da criação do código de produção

◦ Código mais simples

◦ Algoritmos confiáveis

◦ Menor custo de manutenção

Page 3: Teste unitário
Page 4: Teste unitário

Aumento de complexidade em cenários de testes funcionais (interface de usuários, repositórios)

Apoio gerencial

Testes falhos causam programas falhos

Testes de cobertura

Lacunas de testes

Falso senso de segurança (TDD não é bala de prata)

Page 5: Teste unitário

Testes requerem visibilidade dos métodos

Encapsulamento requer esconder métodos

Use nomes de pacotes iguais ◦ Classe de produção está no pacote com.foo.bar

◦ Classe de teste deve ficar no pacote com.foo.bar

Use modificadores protected

e package (default)

Page 6: Teste unitário

Testes requerem comportamento específicos

Testes requerem objetos controláveis

Testes requerem Mocks

Frameworks de Mocks◦ Mockito

◦ EasyMock

◦ PowerMock

Page 7: Teste unitário

Framework de Mock◦ Simples

◦ Claro

◦ Intuitivo (depois que você entende sua lógica)

◦ Versão atual 1.9.0

◦ Documentação e notícias http://code.google.com/p/mockito/

Page 8: Teste unitário

@Test

public void myTest() {

SomeObject myMock = Mockito.mock(SomeObject.class);

}

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations =

{"/applicationContext.xml"})

public class SourceCheckerTest {

@Autowired

SourceChecker sourceChecker;

@Mock

SourceRepository mockRepository;

@Before

public void before() {

MockitoAnnotations.initMocks(this);

}

Page 9: Teste unitário

Adiciona um comportamento a um dado método de um mock

public SourceVO getSource(RequestVO request) {

SourceVO sourceVO = null;

sourceVO = repository.loadById(request.getSourceId());

}

@Test

public void procuraSourceExistenteTest() throws RepositoryException {

SourceVO sourceVO = getSourceVO();

String sourceId = sourceVO.getId().toString();

Mockito.when(mockRepository.loadById(sourceId)).thenReturn(sourceVO);

RequestVO request = Given.request();

request.setSourceId(sourceId);

SourceVO source = sourceChecker.getSource(request);

}

Page 10: Teste unitário

//Retorna dado valor

Mockito.when(mockRepository.loadById(sourceId)).thenReturn(sourceVO);

//Retorna exceção

Mockito.when(mockRepository.loadById(sourceId)).thenThrow(new NullPointerException());

//Chama o método real

Mockito.when(mockRepository.loadById(sourceId)).thenCallRealMethod();

//Cria uma resposta customizada

Mockito.when(mockRepository.loadById(sourceId)).thenAnswer(…);

Page 11: Teste unitário

//Retorna dado valor

Mockito.when(counter.getId()).thenReturn(1).thenReturn(2).thenReturn(3). thenThrow(new

NullPointerException());

É possível programar ações consecutivas para um dado método. Muito útil quando se quer ações diferentes a cada chamada de método. Ex.: Loop

Page 12: Teste unitário

Mock é feito com a comparação de objetos, muitas vezes não temos o objeto exato para se compararMockito.when(lotteryMock.theChosenOne(Mockito.anyMap())).thenReturn(categId);

Mockito.any();

Mockito.any(CampaignVO.class);

Mockito.anyBoolean();

Mockito.anyInt();

Mockito.anyCollection();

Mockito.anyCollectionOf(String.class);

Mockito.anyList();

Mockito.anyListOf(Integer.class);

Mockito.anyVararg();

Matchers customizados também podem ser criados mas a sua utilização é muito rara

Page 13: Teste unitário

Métodos void são um caso a parte para o Mockito pois o when recebe o método a ser mockado como parâmetro e o compilador java não aceita isso

public static void main(String[] args) {

System.out.println(getNum()); //OK

System.out.println(getVoid()); // ERROR

}

private static Integer getNum() {

return 5;

}

private static void getVoid() { }

Page 14: Teste unitário

Uso dos métodos doThrow e doCallRealMethod

Mockito.doThrow(NullPointerException.class).when(sourceRepository).loadById("123456");

Mockito.doCallRealMethod().when(sourceRepository).loadById("123456");

Page 15: Teste unitário

Os mocks conseguem retornar objetos controlados mas as vezes deseja-se interceptar a chamada para alterar a resposta, verificar os parâmetros passados e executar ou não o método real para isso existe o Answer

Evite usar answer, procure soluções mais simples.

Page 16: Teste unitário

Dentro do AdServer o Answer foi usado para validar a passagem de argumentos em métodos complexos

public void makeSearch(CampaignVO campaign) {

changeCampaignName(campaign);

changeOtherValue(campaign);

repository.search(campaign); // What are the campaign's attributes?

}

Ex.: Desejo validar a campanha passada no repositório já que essa campanha pode ter sido alterada por métodos intermediários

Page 17: Teste unitário

Mockito.doAnswer(new Answer<Map<Long, Double>>() {

public Map<Long, Double> answer(InvocationOnMock invocation) {

Object[] args = invocation.getArguments();

// valida país recebido

List<AdVO> adVO = (List<AdVO>) args[0];

Assert.assertTrue(adVO.size() == 1);

Assert.assertEquals("728_90", adVO.get(0).getDimension());

return values;

}

}).when(adSelectorSpy).createAdsValues(adList);

Valido se o primeiro argumento passado possui um elemento e se esse elemento tem um valor específico

Page 18: Teste unitário

O que acontece se você deseja controlar apenas uma parte de um objeto? ◦ Ex.: Deseja-se testar um método que chama outro

método dentro da mesma classe

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations =

{"/applicationContext.xml"})

public class SourceCheckerTest {

@Autowired

SourceChecker sourceChecker;

SourceChecker checkerSpy;

@Before

public void before() {

checkerSpy = Mockito.spy(sourceChecker);

}

Espiamos o comportamentode um método real

Page 19: Teste unitário

Um pouco de teoria

◦ Quando um método é mockado ele é executado, porém como ele não existe, não há problema

◦ Mockar um método de um objeto espionado faz o método ser executado, porém como ele é real isso pode causar problemas

◦ Spies devem usar métodos doThrow, doReturn e doNothing

◦ MOCKS NUNCA executam métodos reais até que digamos o contrário (thenCallRealMethod ou doCallRealMethod), SPIES SEMPRE executam métodos reais até que digamos o contrário (doNothing)

Page 20: Teste unitário

@Autowired

TestFilter filter;

TestFilter filterMock;

@Test

public void filtroNaoPreValidadoTest() {

filterMock = Mockito.spy(filter);

Mockito.doReturn(false).when(filterMock.preValidate(Mockito.any(CampaignVO.class)));

List<CampaignVO> campaignList = createCampaignList();

filterMock.doFilter(createSource(), campaignList);

}

Page 21: Teste unitário

O Mockito também consegue validar o comportamento dos métodos reais, verificando quantas vezes um método foi ou não chamado, em qual ordem, etc

A validação de comportamento pode ser muito útil em classes de transformações ou validadores

Page 22: Teste unitário

O Mockito também consegue validar o comportamento dos métodos reais, verificando quantas vezes um método foi ou não chamado, em qual ordem, etc

A validação de comportamento pode ser muito útil em classes de transformações ou validadores

Page 23: Teste unitário

Valido que uma chamada não ocorreu

@Autowired

TestFilter filter;

TestFilter filterMock;

@Test

public void filtroNaoPreValidadoTest() {

filterMock = Mockito.spy(filter);

Mockito.doReturn(false).when(filterMock.preValidate(Mockito.any(CampaignVO.class)));

List<CampaignVO> campaignList = createCampaignList();

filterMock.doFilter(createSource(), campaignList);

// Não passou na prevalidação não deve chamar o filtro

Mockito.verify(filterMock, Mockito.never()).filter(Mockito.any(CampaignVO.class),

Mockito.any(SourceVO.class));

}

Page 24: Teste unitário

Testar um validador.

public boolean validatesCampaignToAlter(CampaignVO campaignVO) {

boolean resp = false;

if (validateBanners(campaignVO) && validateStartDate(campaignVO) &&

validateCategory(campaignVO) && validateCountry(campaignVO) && validateId(campaignVO)) {

resp = true;

}

return resp;

}

@Test

public void alteracaoCampanhaNegadaSemBanner() {

CampaignVO campaign = new CampaignVO();

campaign.setHas_banners((byte) 0);

Assert.assertFalse(validatorSpy.validatesCampaignToAlter(campaign));

Mockito.verify(validatorSpy, Mockito.times(1)).validateBanners(campaign);

Mockito.verify(validatorSpy, Mockito.never()).validateStartDate(campaign);

Mockito.verify(validatorSpy, Mockito.never()).validateCategory(campaign);

Mockito.verify(validatorSpy, Mockito.never()).validateCountry(campaign);

Mockito.verify(validatorSpy, Mockito.never()).validateId(campaign);

Page 25: Teste unitário

Testes muitas vezes obriga a mudar atributos privados de uma classe, como suas dependências.

O Spring Testing possui uma classe chamada ReflectionTestUtils com vários métodos úteis

// Adiciona o objeto sourceCheckerMock dentro do objeto businessMock,

// sendo esse atributo chamado “sourceChecker”

ReflectionTestUtils.setField(target, “atrributeName", objectToInsert);

Boolean slaveCrash = (Boolean) ReflectionTestUtils.getField(target, “attributeToRead");

Page 26: Teste unitário

O Spring Testing também possui algumas ferramentas para se testar controllers e emular chamadas HTTP

Page 27: Teste unitário

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration({"/applicationContext.xml", "/springmvc-servlet.xml"})

public class CacheStatusControllerTest {

@Autowired

private ApplicationContext applicationContext;

@Autowired

private CacheStatusController controller;

private MockHttpServletRequest request = new MockHttpServletRequest();

private MockHttpServletResponse response = new MockHttpServletResponse();

private AnnotationMethodHandlerAdapter handler;

Deve-se carregar o contexto da aplicação e o do MVC

Deve-se carregar o controller necessário

Deve-se criar um handler e um Mock do Request e Response

Page 28: Teste unitário

@Before

public void before() {

// Recupera handler para a chamada ao Controller

handler = applicationContext.getBean(AnnotationMethodHandlerAdapter.class);

// Habilita recuperação do conteúdo do response

response.setOutputStreamAccessAllowed(true);

}

O Handler deve ser associado o Handler usado no Spring (talvez seja um pouco chato descobrir isso)

Caso deseje-se ler o conteúdo do response, o que é o mais comum, deve-se setar o acesso ao OutputStream

Page 29: Teste unitário

@Test

public void validateCacheStatus() throws Exception {

// Prepara método e url de chamada

request.setMethod("GET");

request.setRequestURI("/status/cache.html");

request.setParameter(“update", “true");

handler.handle(request, response, controller);

Assert.assertEquals("Informações incorretas", expectedResponse(),

response.getContentAsString());

}

O request deve ser setado com o método desejado (GET,POST,PUT,etc)

A URL de ser setada na URI do request

Caso haja parâmetros esses devem ser setados no request

Para executar a chamada utilize o método handle do Handler capturado

Para ler a resposta, caso tenha setado essa opção no response, utilize o método getContentAsString (ou outro formato desejado)

Page 30: Teste unitário

Quando utilizar o Spring como seu framework de Injeção de Dependência, prefira sempre as configurações por anotações ao invés do XML, porém vale lembrar que essa última configuração sobrescreve qualquer anotação feita.

Certos cenários de teste necessitam de situações especiais, não hesite em configurar o contexto para que a situação seja contemplada. Ex.: Ligar ou desligar transações, ler outro arquivo de propriedades, ligar ou desligar aspectos, etc.

Page 31: Teste unitário

Mockito◦ http://code.google.com/p/mockito/

TDD◦ http://pt.wikipedia.org/wiki/Test_Driven_Developm

ent

Spring Framework◦ http://static.springsource.org/spring/docs/3.1.x/s

pring-framework-reference/html/

Spring Testing◦ http://static.springsource.org/spring/docs/3.1.x/s

pring-framework-reference/html/testing.html