testes de software & tdd - engenharia de sistemas de ... · depurarvs.testar...

Post on 11-Aug-2020

2 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

TESTES DE SOFTWARE & TDDENGENHARIA DE SISTEMAS DE INFORMAÇÃO

Daniel Cordeiro2 de outubro de 2019

Escola de Artes, Ciências e Humanidades | EACH | USP

DEPURAR VS. TESTAR

Everyone knows that debugging is twice as hard as writing aprogram in the first place. So if you’re as clever as you canbe when you write it, how will you ever debug it?

Brian Kernighan, The Elements of Programming Style

Program testing can be used to show the presence of bugs,but never to show their absence!

Edsger W. Dijkstra, Notes On Structured Programming

1/19

TESTE MODERNO

Antes• desenvolvedores terminavam de escrever o código e faziamalguns testes ad hoc

• código era “jogado” pro pessoal de Quality Assurance (QA)• pessoal de QA mexia manualmente no programa

Hoje/Ágil

• teste é parte de todas as iterações Ágil• desenvolvedores testam o seu próprio código• ferramentas & processos de testes totalmente automatizados• equipe de testes/QA encarregada de melhorar as ferramentas etestabilidade do código

2/19

TESTE MODERNO

Antes• desenvolvedores terminavam de escrever o código e faziamalguns testes ad hoc

• código era “jogado” pro pessoal de Quality Assurance (QA)• pessoal de QA mexia manualmente no programa

Hoje/Ágil

• teste é parte de todas as iterações Ágil• desenvolvedores testam o seu próprio código• ferramentas & processos de testes totalmente automatizados• equipe de testes/QA encarregada de melhorar as ferramentas etestabilidade do código

2/19

A QUALIDADE DO SOFTWARE É RESULTADO DE UMBOM PROCESSO E NÃO A RESPONSABILIDADE DE UM

GRUPO ESPECÍFICO.

2/19

BDD + TDD

Projeto guiado por comportamento (BDD)

• desenvolva histórias de usuários (as funcionalidades que vocêquer ter) para descrever como o app irá funcionar

• usando Cucumber, histórias de usuários viram testes deaceitação e testes de integração

Desenvolvimento guiado por testes (TDD)• cada definição de passo para uma nova história pode precisarque se desenvolva novo código

• TDD advoca que: escreva os testes de unidade & funcionaisprimeiro, antes de escrever o código

• ou seja, escreva testes para o código que você gostaria de ter

3/19

CUCUMBER & RSPEC

• Cucumberdescreve ocomportamentocom asfuncionalidades& cenários(projeto guiadopelocomportamento)

• RSpec testa osmódulosindividuais quecontribuem comessescomportamentos(desenvolvimentoguiado por testes)

Cucumber stepfalhando (vermelho)

Teste RSpec falhando (vermelho)

Teste RSpec passando (verde)

Cucumber step passando (verde)

4/19

PILHA DE TESTES

Cucumber

CapybaraCapybara

Rack::TestRack::Test

RSpecRSpec

RackRack

Rails appRails app

SeleniumSelenium

browserbrowser

web serverweb

serverSaaS app

SaaS app

rspec-rails gemrspec-rails gem

Testes deIntegração

Testes de Unidadee funcionais

5/19

FIRST, TDD E RSPEC

TESTES DE UNIDADE DEVEM SER FIRST

F ast (rápido)I ndepenent (independente)R epeatable (repetível)S elf-checking (autoverificável)T imely (oportuno)

6/19

TESTES DE UNIDADE DEVEM SER FIRST

Rápido rodar (um subconjunto dos) testes deve ser rápido (jáque você vai fazer isso o tempo todo)

Independente testes não devem depender uns dos outros, vocêdeve poder rodá-los quaisquer testes em qualquerordem

Repetível N execuções sempre devem produzir o mesmoresultado (para ajudar a isolar bugs e permitir aautomação)

Autoverificável testes devem poder detectar por si mesmos seforam bem sucedidos (não deve haver uma pessoapara verificar os resultados)

Oportuno escrito quase que ao mesmo tempo que o código queserá testado (com TDD, é escrito antes do código!)

7/19

TESTES DE UNIDADE DEVEM SER FIRST

Rápido rodar (um subconjunto dos) testes deve ser rápido (jáque você vai fazer isso o tempo todo)

Independente testes não devem depender uns dos outros, vocêdeve poder rodá-los quaisquer testes em qualquerordem

Repetível N execuções sempre devem produzir o mesmoresultado (para ajudar a isolar bugs e permitir aautomação)

Autoverificável testes devem poder detectar por si mesmos seforam bem sucedidos (não deve haver uma pessoapara verificar os resultados)

Oportuno escrito quase que ao mesmo tempo que o código queserá testado (com TDD, é escrito antes do código!)

7/19

TESTES DE UNIDADE DEVEM SER FIRST

Rápido rodar (um subconjunto dos) testes deve ser rápido (jáque você vai fazer isso o tempo todo)

Independente testes não devem depender uns dos outros, vocêdeve poder rodá-los quaisquer testes em qualquerordem

Repetível N execuções sempre devem produzir o mesmoresultado (para ajudar a isolar bugs e permitir aautomação)

Autoverificável testes devem poder detectar por si mesmos seforam bem sucedidos (não deve haver uma pessoapara verificar os resultados)

Oportuno escrito quase que ao mesmo tempo que o código queserá testado (com TDD, é escrito antes do código!)

7/19

TESTES DE UNIDADE DEVEM SER FIRST

Rápido rodar (um subconjunto dos) testes deve ser rápido (jáque você vai fazer isso o tempo todo)

Independente testes não devem depender uns dos outros, vocêdeve poder rodá-los quaisquer testes em qualquerordem

Repetível N execuções sempre devem produzir o mesmoresultado (para ajudar a isolar bugs e permitir aautomação)

Autoverificável testes devem poder detectar por si mesmos seforam bem sucedidos (não deve haver uma pessoapara verificar os resultados)

Oportuno escrito quase que ao mesmo tempo que o código queserá testado (com TDD, é escrito antes do código!)

7/19

TESTES DE UNIDADE DEVEM SER FIRST

Rápido rodar (um subconjunto dos) testes deve ser rápido (jáque você vai fazer isso o tempo todo)

Independente testes não devem depender uns dos outros, vocêdeve poder rodá-los quaisquer testes em qualquerordem

Repetível N execuções sempre devem produzir o mesmoresultado (para ajudar a isolar bugs e permitir aautomação)

Autoverificável testes devem poder detectar por si mesmos seforam bem sucedidos (não deve haver uma pessoapara verificar os resultados)

Oportuno escrito quase que ao mesmo tempo que o código queserá testado (com TDD, é escrito antes do código!)

7/19

RSPEC

• Linguagem específica de domínio (DSL) para testes.• DSL são pequenas linguagens de programação que simplificamuma tarefa, mas que normalmente são menos generalizáveis

• Exs: migrações, expressões regulares, SQL

• Testes em RSpec são chamados de specs ou exemplos• Para rodar os testes em um arquivo: rspec <arquivo>• Ou melhor: use guard/autotest

8/19

EXEMPLO DE RSPEC

expect { k += 1.05 }.to change { k }.by( a_value_within(0.1).of(1.0) )

expect { s = "barn" }.to change { s }.from( a_string_matching(/foo/) ).to( a_string_matching(/bar/) )

expect(["barn", 2.45]).to contain_exactly(a_value_within(0.1).of(2.5),a_string_starting_with("bar")

)

expect(["barn", "food", 2.45]).to end_with(a_string_matching("foo"),a_value > 2

)

expect(["barn", 2.45]).to include( a_string_starting_with("bar") )

expect(:a => "food", :b => "good").to include(:a => a_string_matching(/foo/))

https://github.com/rspec/rspec-expectations

9/19

require 'ruby_intro.rb'

describe BookInStock doit "should be defined" doexpect { BookInStock }.not_to raise_error

end

describe 'getters and setters' dobefore(:each) { @book = BookInStock.new('isbn1', 33.8) }it 'sets ISBN' do

expect(@book.isbn).to eq('isbn1')endit 'sets price' doexpect(@book.price).to eq(33.8)

endit 'can change ISBN' do@book.isbn = 'isbn2'expect(@book.isbn).to eq('isbn2')

endit 'can change price' do@book.price = 300.0expect(@book.price).to eq(300.0)

endend

expect { lambda }.to(assertion)expect(expression).to(assertion)

10/19

PERGUNTA

Quais tipos de código podem ser testados de forma Repetível eIndependente?

1. Código que depende de aleatoriedade (ex: misturar um baralhode cartas

2. Código que depende do horário do dia (ex: faz backup tododomingo à meia-noite)

Resposta:

• só (1)• só (2)• tanto (1) quanto (2)• nem (1) nem (2)

11/19

DESENVOLVENDO O TESTE PRIMEIRO

• Pense naquilo que seu código deveria fazer• Capture a ideia em um teste, que irá falhar• Escreva o código mais simples possível que faria o código doteste passar

• Refatore. Simplifique o que for comum a vários testes• Continue com a próxima coisa que o código deveria fazer

Vermelho–Verde–RefatoreTente “sempre ter código funcionando”

12/19

O QUE É ESPECÍFICO DE RAILS?

• Métodos adicionais mixed1 no RSpec para permitir testes decoisas específicas do Rails:

• ex: get, post, put para testar controladores• objeto response também para os controladores

• Matchers para testar o comportamento dos apps Rails:• expect(response).torender_template("movies/index")

• Permite criar vários dublês (doubles) para testes em métodosmais complicados

1Mixins em Ruby são uma forma de emular herança múltipla

13/19

EXEMPLO

• Imagine uma nova funcionalidade: adicionar filme usando infoimportada do TMDb

• Como os passos da história de usuário deveriam se comportar?

When I fill in "Search Terms" with "Inception"And I press "Search TMDb"Then I expect to be on the RottenPotatoes homepage...

Lembre-se que em RailsAdicionar uma nova funcionalidade implica em adicionar uma novarota + novo método de controlador + nova visão.

14/19

COMO TESTAR ALGUMA COISA “DE FORMA ISOLADA”SE ELE TIVER DEPENDÊNCIAS QUE PODEM AFETAR OS

TESTES?

14/19

O CÓDIGO QUE GOSTARÍAMOS DE TER

O que o método do controlador deveria fazer quando receber osdados do formulário de busca?

1. chamar um método que irá procurar no TMDb pelo filmeespecificado

2. se o filme for encontrado, selecione (nova) visão “SearchResults” para mostrar os dados do filme

3. se não for encontrado, redirecionar para a página principal comuma mensagem de erro

15/19

O CÓDIGO QUE GOSTARÍAMOS DE TER

require 'rails_helper'

describe MoviesController dodescribe 'searching TMDb' doit 'calls the model method that performs TMDb search'it 'selects the Search Results template for rendering'it 'makes the TMDb search results available to that template'

endend

16/19

TDD PARA A AÇÃO DO CONTROLADOR

• Adicione uma rota a config/routes.rb:post '/movies/search_tmdb (convenção ao invés deconfiguração fará o rails mapear a rota paraMoviesController#search_tmdb)

• Crie uma visão vazia:$ touch app/views/movies/search_tmdb.html.haml

• Crie um método em movies_controller.rb vazio:def search_tmdbend

17/19

E O MÉTODO DO MODELO?

• Chamar o TMDb é responsabilidade do modelo... mas ainda nãoexiste um método de modelo!

• Sem problemas... nós vamos fazer uma chamada “falsa” aométodo que nós gostaríamos de ter, Movie.find_in_tmdb

• Esquema geral:• Simular o POST de um formulário de busca para a ação docontrolador

• Verificar que a ação do controlador irá tentar chamarMovie.find_in_tmdb com os dados desse formulário de busca

• O teste irá falhar porque o controlador não vai chamar o métodofind_in_tmdb (ele ainda está vazio!)

• Arrumar a ação do controlador e fazer o teste ficar verde

18/19

require 'rails_helper'

describe MoviesController dodescribe 'searching TMDb' doit 'calls the model method that performs TMDb search' do

expect(Movie).to receive(:find_in_tmdb).with('hardware')post :search_tmdb, {:search_terms => 'hardware'}

endit 'selects the Search Results template for rendering'it 'makes the TMDb search results available to that template'

endend

19/19

top related