Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testes Unitários na Plataforma iOS

Testes Unitários na Plataforma iOS

Inácio Ferrarini

November 25, 2016
Tweet

More Decks by Inácio Ferrarini

Other Decks in Programming

Transcript

  1. Inácio Ferrarini - https:/ /github.com/inacioferrarini - Programador Java desde 2004

    - OCPJD 6, OCPWCD 5 - Programador iOS desde 2014 - Graduado em Sistemas de Informação pela FRB (2008) - Pós-Graduado em Desenvolvimento de Aplicativos e Games para Dispositivos Móveis pela FIAP (2015) - Contribuinte Open Source - Autor do POD York
  2. Testes - Para que? A segurança em se alterar um

    código é inversamente proporcional ao percentual de cobertura por testes unitários. Não é um mero preciosismo. 70% de cobertura por testes unitários parece alto, porém, resulta em 30% de chance de se causar mudança não intencional que só será percebida posteriormente (geralmente, quando o código está em produção). Apesar de parecer irreal, 100% de cobertura por testes unitários veda alterações indesejadas em produção.
  3. Testes Unitários Visa garantir que “do método para fora”, seu

    comportamento não foi alterado. Assegura que alterações feitas no código não causaram impacto indesejado em quem o utiliza. Idealmente, testa pontualmente um método. Porém, na realidade é comum agrupar pequenos conjuntos comuns de funcionalidade e as testar em conjunto.
  4. Mocking Objeto “impostor”. Utilizado em desenvolvimento quando os objetos finais

    não estão prontos. Possibilita que as demais funcionalidades dependentes do objeto sejam feitas antes do objeto final estar completo. Utilizado em testes para simplificar os cenários. Ao invés de utilizar uma grande quantidade de código para montar o cenário de testes - muitas vezes composto de uma grande quantidade de objetos auxiliares, que não são o interesse do cenário - estes objetos são trocados para facilitar o cenário de interesse. Existem mocks parciais (partial mock), mocks completos (full mock), e mocks para protocolos (protocol mock).
  5. Mocking Mocks para protocolos são utilizados para evitar se implementar

    um protocolo para fins de teste, nos casos em que apenas se precisa verificar se o método foi chamado (verify). Mocks parciais alteram a classe do objeto “mockado”. Chamadas com referência ao objeto original serão afetadas também. Mocks completos facilitam o uso de classes com métodos de init estáticos (ex: Singletons). Deve-se usar o mock parcial sempre que possível.
  6. Observações No contexto do Objective-C, o framework de mock utiliza

    swizzling para substituir uma implementação (IMP) pela desejada. Este objeto é um stub. Funcões em C são chamadas “através” do runtime e, portanto, não podem ser trocadas com swizzling. Desta forma, elas não podem ser “mockadas”. Neste caso, deve-se trocar a lib como um todo. Estudos em andamento. Deve-se desativar o mock ao fim do teste.
  7. Specta (Spec) Testes mais descritivos e agrupamento por contextos semânticos.

    Substitui os testes feitos diretamente com XCTest. Segue o modelo “Given”, “When”, “Then" “AAA" : “Arrange”, “Act”, “Assert”: Preparar o Cenário. Execute o método a ser testado. Verifique o resultado esperado.
  8. Specta (Spec) - Cont. SpecBegin(NomeDoSpec); describe(@“Descreva o Cenário", ^{ context(@“Contexto

    1", ^{ describe(@“o que eu vou testar", ^{ }); describe(@“outra coisa que eu vou testar no mesmo contexto", ^{ }); }); }); SpecEnd
  9. Specta (Spec) - Cont. SpecBegin(NomeDoSpec); describe(@“Descreva o Cenário", ^{ context(@“Ao

    criar o objeto do tipo x", ^{ __block id mockObj = nil; beforeEach(^{ mockObj = OCMPartialMock([MyRealObject new]); }); it(@“ele deve definir x como 1", ^{ expect(mockObj.x).to.equal(1); }); }); }); SpecEnd
  10. Expecta (expects) Simplifica o uso de asserts. Síncrono: expect(success).to.beFalsy(); expect(resp.identifier).toNot.beNil();

    expect(resp.identifier).to.beKindOf([NSString class]); expect(resp.identifier).to.equal(@"1500052111"); Assíncrono (ex: esperar uma animação concluir): expect(finallyBlockWasCalled).after(1).to.beTruthy(); expect(blockWasCalled).after(0.4).to.beTruthy(); expect(alert.alpha).after(0.4).to.equal(0);
  11. OCMock Framework para criação de stubs para testes. Provê diversas

    abstrações e métodos utilitários que simplificam o seu uso. Swizzling “sem dor”.
  12. OHHTTPStubs Testes devem rodar offline. Cria stubs para chamadas de

    rede. Possibilita que uma chamada a um endpoint específico utilizando um verbo HTTP específico retorne imediatamente um conteúdo definido pelo teste em questão. Este conteúdo pode ser criado a partir de um “fixture" local ou pode ser composto utilizando clojures. Possibilita definir todos os parâmetros da requisição HTTP retornada.
  13. Funcionalidades Não-Públicas Apesar de Objective-C possuir escopo de visibilidade (@private),

    o que é comum se fazer é definir a @property ou @selector diretamente no arquivo de implementação - .m. Porém, para que elas sejam acessíveis ao teste, que é uma classe externa, elas precisam estar visíveis ao mesmo. Uma categoria pode ser criada para expor aos testes funcionalidades não-públicas. Use com bom senso.
  14. Pontos de Atenção Contextos devem ser agrupados para melhor organização

    e legibilidade. Agrupar os cenários em contextos permitem que beforeEach, beforeAll, afterEach e afterAll compartilhem código que seria repetido para todos os teste de um determinado contexto. O Contexto que criar o mock deve finalizar o uso do mesmo. Idealmente, testes devem apontar de forma inequívoca para o que foi quebrado.
  15. Pontos de Atenção - Cont. Singletons, variáveis estáticas, estado global

    agregam complexidades aos cenários de teste: Estados compartilhados influenciam em pontos não previstos - Um teste pode quebrar por valores modificados por outros testes não relacionados, mas que compartilham um estado global. Valores alterados em um teste serão propagados a todos os demais testes.
  16. Relatório de Cobertura $ xcodebuild clean build -workspace <projeto>.xcworkspace -scheme

    <UnitTestScheme> -destination 'platform=iOS Simulator,name=iPhone 5s' VALID_ARCHS=x86_64 test | xcpretty $ bundle exec slather > /dev/null
  17. Extra - Configuração do Ambiente $ ruby -e "$(curl -fsSL

    https:/ /raw.githubusercontent.com/Homebrew/ install/master/install)" $ brew install rbenv ruby-build $ echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile $ source ~/.bash_profile $ rbenv install 2.3.1 $ rbenv global 2.3.1 $ gem install bundler $ bundle install
  18. www.concretesolutions.com.br blog.concretesolutions.com.br Rio de Janeiro – Rua São José, 90

    – cj. 2121 Centro – (21) 2240-2030 São Paulo - Av. Nações Unidas, 11.541
 3º andar - Brooklin - (11) 4119-0449