Princípios de usabilidade em aplicativos móveis

Reblogando conteúdo muito bom sobre UX mobile. Na minha opinião também serve para web.

https://www.thinkwithgoogle.com/intl/pt-br/articles/mobile-app-ux-principles.html

 

Os aplicativos móveis estão dando forma a novas expectativas de transação e serviços, portanto, melhorar as experiências dos usuários e as conversões é de extrema importância.

ADOTE

Elimine obstáculos de utilização

O objetivo nesse estágio é remover todos os obstáculos de utilização – e adesão – do seu aplicativo móvel.

Telas de Abertura (Splash Screen), Dicas & Técnicas de Ativação

Faça com que os usuários sintam-se engajados pelo conteúdo/substância o mais rápido possível para que eles possam utilizar e analisar o valor do aplicativo para eles. A primeira impressão conta, e a tela de abertura (splash screen) oferece uma janela pequena, mas crucial para engajar o usuário com a sua proposta. Opções de Dicas/Ajuda ou uma sequência de Técnicas de Ativação só devem ser implementadas se absolutamente necessário – nunca deixe os usuários esperando.

Tela Inicial & Navegação

A tela inicial de um aplicativo deve proporcionar ao usuário jornada(s) e funcionalidades para completar suas tarefas prioritárias, além de proporcionar conteúdo que atende as suas expectativas. A navegação deve ser clara, com foco na tarefa e na lógica, e consistente por todo o aplicativo. Apenas a navegação e o conteúdo primário devem ser visíveis na configuração padrão, com o conteúdo secundário escondido – porém, disponível através de cliques e deslizes – fora da tela.

Cadastro, Log-In e Permissões

Um dos grandes pontos de diferença entre aplicativos móveis e sites móveis é que os aplicativos permitem que os usuários se mantenham logados por mais tempo (eliminando o esforço de log-in manual e erros), recebendo os benefícios do nível de conveniência e personalização, derivados das suas informações, comportamentos e histórico de transações. Mas não solicite um cadastro a não ser que absolutamente necessário para proporcionar esse tipo de valor para o usuário.

USE

Simplifique decisões de conversão

O foco nesse estágio é permitir que as pessoas rapidamente busquem o que estão procurando, pesquisem e considerem produtos e serviços e continuem na sua jornada de transação entre diversos dispositivos.

Busca

Uma ótima ferramenta de busca ajudará os usuários a encontrarem o que estão buscando de maneira rápida e fácil, atingindo o objetivo de satisfazer suas necessidades e impulsionar o índice de conversão. Geralmente, a busca em aplicativos apresenta um nível de conversão muito mais alto do que a utilização sem busca, refletindo a intenção maior do consumidor. Existem diversas maneiras de permitir a busca, de palavras-chave a leitura óptica do produto até buscas por imagem.

Produtos & Serviços

As telas de produto são onde os usuários fazem suas decisões de conversão-chave, por exemplo: adicionar ao carrinho, adicionar à lista de desejos, reservar agora, ligar agora, preencher o formulário, etc. E boas telas de produto permitem que os usuários concluam a transação rapidamente, salvem os dados para depois e compartilhem os itens sobre os quais eles devem tomar alguma decisão.

Entre Dispositivos e Off-Line

Com o aumento de consumidores fazendo pesquisas em dispositivos móveis e convertendo em outras sessões ou em outro dispositivo ou na própria loja, é extremamente importante que os aplicativos permitam que os usuários façam a transição perfeita entre pontos de contato físicos e digitais rumo à conversão.

FACILITE A TRANSAÇÃO

Proporcione o máximo de conveniência

O objetivo nesse momento é ajudar os usuários a avançarem em cada etapa do check-out empenhando o mínimo de esforço e contando com mensagens confiáveis suficientes para realizarem a conversão sem pensar duas vezes.

Na etapa do carrinho compras, devemos dar o impulso necessário para que o usuário realize o check-out (para converter) ou continue comprando (para aumentar o valor médio do carrinho); confirmar todos os itens e os custos; e permitir que o usuário edite os itens. Na etapa de pagamento: devemos empregar métodos práticos de captação de dados – por exemplo, leitura óptica de cartões, pagamento express – e o preenchimento automático de dados para usuários recorrentes. Na etapa de check-out e confirmação devemos remover distrações que não levam à conversão; exibir opções de atendimento; fornecer check-out de uma única tela para usuários recorrentes; confirmar os principais detalhes da transação; e exibir conteúdo contextual que agregue valor além da operação imediata (e que contribua para a retenção).

RETORNE

Self-service, engajamento e satisfação (ou encantamento)

Durante esta etapa, o foco principal é ser útil, gerar engajamento e satisfação (encantamento) para reter consumidores ou incentivar fidelidade.

Conta & Senhas

Conta: os aplicativos são o ponto de contato ideal para consumidores e membros servirem a si mesmos, assim como administrarem suas contas e transações a qualquer hora e em qualquer lugar. Dê o controle e o nível de conveniência que apenas aplicativos móveis podem proporcionar aos seus consumidores.

Senhas: permita que os usuários recebam e resgatem senhas ou vouchers no aplicativo, visualizem seu status de fidelidade ou recebam atualizações quando algo for alterado – e elimine a necessidade de imprimir e portar garantias físicas.

Conteúdo & Design

Otimize a experiência do usuário com conteúdo adequado, tom de voz, design visual, utilização de motion design sutil, e ofereça melhores formas de descobrir conteúdos e itens – e garanta que os usuários nunca se deparem com becos sem saída.

Widgets e Notificações

Widgets: são extensões do app contidas dentro do seu aplicativo móvel principal que permitem que você publique pílulas de informação de alto valor e em momentos oportunos para usuários específicos, as quais são exibidas no smartphone do usuário para serem visualizadas e digeridas rapidamente.

Notificações: são mensagens que avisam os usuários de eventos altamente relevantes, pessoais e oportunos, assim como conteúdos ou mensagens. As notificações funcionam em modo stream no plano de fundo, até que o usuário identifique ou ouça um alerta.

Para ter acesso a todos os princípios de UX e as métricas-chave para mensuração, faça o download do relatório completo.

Deixe um comentário

Lead time explicado

Deixe um comentário

Metodos Ageis e seus mitos

Um pequeno “draft” do que Mauricio Aniche (Caelum) apresentou de Métodos ágeis: o que é folclore e o que é real?

Em uma rápida pesquisa nos participantes, a maioria levatou a mão ao perguntar que utiliza metodologia ágil (cerca de 70 de 100).

Aniche declarou que  a ciência (em seu mestrado e doutorado) o deixou mais frio, deixou a paixão do agile e se concentrou apenas em resultados.

Indicou leitura de Leprechauss of software engineering >> acredito que seja: https://leanpub.com/leprechauns

O principal da palestra foi que os testes unitários levam um tempo para se tornar hábito.

Conforme a equipe ganha maturidade ai vai procurando outras ferramentas para auxiliar as entregas de software funcionando.

 

Deixe um comentário

Internacionalização colaborativa

A ideia de colaboração realmente deve invadir o desenvolvimento de software. Para sistemas que são mundiais é interessante ter um processo eficaz de internacionalizar a linguagem do software.

Descobri hoje que o sistema de compressão de arquivos B1 é desenvolvido sobre o framework Crowdin, uma excelente ferramenta para que deseja internacionalizar colaborativamente.

,

Deixe um comentário

Aprendendo TDD (ou Desenvolvimento Orientado a Testes) Python

Reblogado de: http://blog.thiagobelem.net/aprendendo-tdd-ou-desenvolvimento-orientado-a-testes/

Mas afinal, que diabos é TDD?

Segundo a Wikipédia, TDD é:

Test Driven Development (TDD) ou em português Desenvolvimento dirigido guiado por testes é uma técnica de desenvolvimento de software que baseia em um ciclo curto de repetições:

Primeiramente o desenvolvedor escreve um caso de teste automatizado que define uma melhoria desejada ou uma nova funcionalidade. Então, é produzido código que possa ser validado pelo teste para posteriormente o código ser refatorado para um código sob padrões aceitáveis.

Kent Beck, considerado o criador ou o ‘descobridor’ da técnica, declarou em 2003 que TDD encoraja designs de código simples e inspira confiança.

E qual a vantagem disso?

Pra mim, TDD é uma forma de você garantir que, através de pequenos passos, você vai chegar à um “todo-completo”, que é uma aplicação que funciona baseado apenas nas especificações que foram definidas, e lá na frente quando você for mudar algo, é só rodar os testes novamente para garantir que tudo continue funcionando.

Mas por via das dúvidas, pesquisem mais sobre o assunto, tem um mundo por trás disso tudo.

“Talk is cheap! Shut up and show me the code!”

(eu amo essa frase)

Vamos direto ao ponto e vamos ver um pequeno exemplo de como criar uma função baseada em TDD… e vamos começar pelo exemplo mais simples e usado por todos: o famoso Fizz Buzz, que segundo a nossa amiga Wikipédia é:

Bizz buzz (also known as fizz buzz, or simply buzz) is a group word game frequently encountered as a drinking game. Players take turns to count incrementally, replacing any number divisible by three with the word “bizz”, and any number divisible by five with the word “buzz”.

Tradução deste que vos fala:

Bizz buzz (também conhecido com fizz buzz, ou apenas buzz) é uma brincadeira em grupo, comummente jogada como desculpa pra encher a cara. Os jogadores jogam em turnos incrementais, onde cada um fala um número substituindo números divisíveis por três pela palavra “fizz“, e números divisíveis por cinco pela palavra “buzz“.

Sendo que você precisa falar “fizz buzz” quando o número for múltiplo de três e de cinco.

Básicamente o resultado final do jogo seria algo assim:

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, Fizz Buzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, Fizz Buzz, 31, 32, Fizz, 34, Buzz, Fizz, …

Então vamos criar uma função FizzBuzz que receba um parâmetro N e retorne o número, fizz, buzz ou fizz buzz dependendo do número que ela recebeu. :)

Antes de qualquer coisa, vou fazer algo que aprendi com esse livro e recomendo muito: vamos montar uma lista de especificações que precisaremos testar/implementar.

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”

Essas não são todas as regras do jogo, mas já é um bom começo… Cada um desses itens vai significar um teste e – possivelmente – uma melhoria no código da função.

Ao longo desse artigo irei copiar essa lista diversas vezes, marcando com negrito os itens que iremos atacar, e riscando os itens que forem concluídos.

Mas peraí… e a linguagem?

Verdade… temos que decidir uma linguagem, e como eu falo MUITO de PHP aqui no blog vamos fazer esse FizzBuzz em Python, que já vem com um framework de testes embutido na linguagem, pra quem quiser brincar de testes unitários no PHP recomendo muito o PHPUnit.

Baby steps, ou “Passos de bebê”

Uma das maiores características do desenvolvimento orientado à testes é que você sempre tente dar passos menores que suas pernas, não significa que você não possa dar uma corrida se o projeto exigir, mas sempre avance com pequenos passos, nada de escrever 100 linhas de código sem testar (com testes)… e eu vou tentar seguir essa metodologia aqui.

Mãos à obra!

No TDD você SEMPRE começa pelo teste, então vamos começar criando nosso arquivo de testes:

#!/usr/bin/env python

import unittest

if __name__ == '__main__':
unittest.main()

Fizemos três coisas no nosso arquivo fizzbuzz_test.py:

  1. Primeiro temos #!/usr/bin/env python que permite que executemos o arquivo sem ser através do executável do Python, mas isso é opcional.
  2. Depois importamos a biblioteca nativa de testes unitários do Python
  3. E por fim usamos uma condição que – resumidamente – permite que o arquivo seja executado pelo terminal já rodando os testes

Quando a gente rodar esse arquivo com o comando ./fizzbuzz_test.py ou o comando python fizzbuzz_test.py vamos ter o seguinte output:

$ python fizzbuzz_test.py

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK
view raw
gistfile1.sh
This Gist brought to you by GitHub.

Então sabemos que tudo está funcionando… prontos para o primeiro teste?

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”

Nosso primeiro teste, da forma mais simples e reduzida possível, ficaria assim:

#!/usr/bin/env python

import unittest

class TestFizzBuzz(unittest.TestCase):

def test_FizzBuzz(self):
self.assertEqual(FizzBuzz(1), 1)

if __name__ == '__main__':
unittest.main()

Criamos uma classe TestFizzBuzz, que é um caso de teste (contém vários testes) para testar a classe/funcionalidade FizzBuzz.

Definimos nosso primeiro teste (test_FizzBuzz), onde fizemos uma asserção (verificação):

O resultado de FizzBuzz(1) é IGUAL a 1?

A asserção de igualdade é justamente o método assertEqual:)

Prontos pra rodar o teste? Vamos ver o que acontece…

$ python fizzbuzz_test.py
E
======================================================================
ERROR: test_FizzBuzz (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 8, in test_FizzBuzz
    self.assertEqual(FizzBuzz(1), 1)
NameError: global name 'FizzBuzz' is not defined

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

UHU! Nosso primeiro erro! (sim, no TDD os testes não passando significam progresso).. mas não é o erro que eu estava esperando! :(

O problema é que nós ainda não definimos FizzBuzz, por isso o Python xiou dizendo “global name ‘FizzBuzz’ is not defined“.

Vamos criar nosso arquivo fizzbuzz.py com o seguinte conteúdo:

#!/usr/bin/env python

def FizzBuzz():
pass
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Criamos a estrutura da nossa função FizzBuzz que ainda não faz nada.

O “pass” no Python é usado quando uma função/método ainda não tem conteúdo.. e como não temos chaves pra dizer onde ela começa e termina, precisamos de uma instrução que faça exatamente nada.

Vamos voltar ao nosso teste e importar essa função para que ela possa ser usada nos nossos testes, depois vamos rodar os testes novamente e ver se aquela mensagem de erro mudou.

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_FizzBuzz(self):
self.assertEqual(FizzBuzz(1), 1)

if __name__ == '__main__':
unittest.main()

A linha “from fizzbuzz import FizzBuzz” significa “Importe a classe/função FizzBuzz do arquivo ou módulo chamado fizzbuzz“… isso mesmo, no Python podemos importar apenas parte de um arquivo! :)

E o resultado da execução dos testes é…

$ python fizzbuzz_test.py
E
======================================================================
ERROR: test_FizzBuzz (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 9, in test_FizzBuzz
    self.assertEqual(FizzBuzz(1), 1)
TypeError: FizzBuzz() takes no arguments (1 given)

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

E estamos chegando lá… agora o Python reclamou que – segundo sua definição – a função FizzBuzz não recebe parâmetros.. que é justamente o primeiro item da nossa lista, então vamos fazer isso acontecer.

#!/usr/bin/env python

def FizzBuzz(numero):
pass
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Isso.. tudo beeeeem de vagar, lembre-se dos passos de bebê!

Agora rodamos os testes novamente e…

$ python fizzbuzz_test.py
F
======================================================================
FAIL: test_FizzBuzz (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 9, in test_FizzBuzz
    self.assertEqual(FizzBuzz(1), 1)
AssertionError: None != 1

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

Conseguimos! O primeiro item da lista foi resolvido! :D

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”

Mas agora temos outro problema… que é justamente a nossa asserção de “FizzBuzz(1) é 1″ falhando.

Fazendo um teste passar

Agora vem a parte (pra mim) mais importante do TDD:

Sempre que você escrever um teste e ele quebrar, pergunte-se: “Qual o menor passo, a menor mudança no código, que eu posso fazer pra esse teste passar?” Não importa se esse passo é elegante, segue padrões de projeto ou está simplesmente enganando o código… A primeira vez que você faz o teste passar tem a ver com velocidade e simplicidade, boas práticas fica pro momento da refatoração, com todos os testes passando.

A menor mudança que a gente pode fazer pra esse código funcionar, sem pensar nos outros casos de FizzBuzz(n) que ainda não estão testados é:

#!/usr/bin/env python

def FizzBuzz(numero):
return 1
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Você pode querer me matar depois dessa, mas não estou brincando.. isso é sério, é assim que a coisa funciona! :)

E os testes?

$ python fizzbuzz_test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

view raw
gistfile1.sh
This Gist brought to you by GitHub.

Satisfação! Finalmente, nosso primeiro teste passou!!!

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”

Decidindo o próximo teste

Quando você estiver decidindo o próximo teste, tente seguir as seguintes dicas:

  • Escreva um teste que você SABE não vai passar.. Não adianta ficar testando coisas que já estão passando, né?
  • Mas se você não tem certeza, escreva o teste e veja o que acontece… Testes nunca são demais.
  • Escreva um teste que você ACHA que pode ser resolvido de forma simples, nada de testar o programa todo de uma vez.. o ideal é que você tenha apenas um teste quebrando em cada “rodada”
  • Teste com valores plausíveis e facilmente compreensíveis… testar soma (1, 2) == 3 é muito melhor do que testar soma (12312512312, 31653341265312) = ????, entendeu onde quero chegar?

Então vamos seguir a lista e testar FizzBuzz(2) que deveria retornar 2, e provavelmente não vai passar por causa do nosso roubo (return 1).

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_FizzBuzz_de1(self):
self.assertEqual(FizzBuzz(1), 1)

def test_FizzBuzz_de2(self):
self.assertEqual(FizzBuzz(2), 2)

if __name__ == '__main__':
unittest.main()

Eu poderia fazer a nova asserção dentro do mesmo teste, mas preferi trocar o nome dele e criar um segundo teste, assim as coisas ficam mais claras e você pode ver cada teste falhando separadamente.

$ python fizzbuzz_test.py
.F
======================================================================
FAIL: test_FizzBuzz_de2 (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 12, in test_FizzBuzz_de2
    self.assertEqual(FizzBuzz(2), 2)
AssertionError: 1 != 2

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

E com esse teste, concluímos que ao roubar (mesmo valendo pra quele momento) acabamos cuspindo pra cima, e agora o cuspe caiu na nossa cabeça… 2 (esperado) é diferente de 1 (resultado).

Mais uma vez, hora de se perguntar: ”Qual o menor passo, a menor mudança no código, que eu posso fazer pra esse teste passar?“.. e se a função retornar o número que recebeu?

#!/usr/bin/env python

def FizzBuzz(numero):
return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Feita a mudança, rodamos os testes e…

$ python fizzbuzz_test.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

view raw
gistfile1.sh
This Gist brought to you by GitHub.

Excelente! Nosso segundo teste está passando e, quase sem perceber, refatoramos o código para algo realmente dentro das regras do problema :)

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”

Qual o nosso próximo teste? Vamos seguir a lista e ver no que vai dar… Se entendemos bem o que fizemos até agora, FizzBuzz(3) vai retornar 3 e não “fizz” como manda a especificação do problema (múltiplos de três retornam “fizz”).

Como voltamos na especificação do problema, vamos adicionar mais um item à nossa lista:

  • FizzBuzz(9) retorna “fizz”

Agora vamos ao teste do FizzBuzz(3) retorna “fizz”:

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_FizzBuzz_de1(self):
self.assertEqual(FizzBuzz(1), 1)

def test_FizzBuzz_de2(self):
self.assertEqual(FizzBuzz(2), 2)

def test_FizzBuzz_de3_retorna_fizz(self):
self.assertEqual(FizzBuzz(3), "fizz")

if __name__ == '__main__':
unittest.main()

E o resultado dos testes, como esperado, falhou:

$ python fizzbuzz_test.py
..F
======================================================================
FAIL: test_FizzBuzz_de3_retorna_fizz (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 15, in test_FizzBuzz_de3_retorna_fizz
    self.assertEqual(FizzBuzz(3), "fizz")
AssertionError: 3 != 'fizz'

----------------------------------------------------------------------
Ran 3 tests in 0.000s

FAILED (failures=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

Minha função FizzBuzz ainda não está preparada para retornar fizz, o teste quebrou e nós progredimos em direção a solução de mais um problema… viu como é legal?

Eu sei que você está querendo começar a correr e verificar se numero é múltiplo de três, mas não temos testes pra isso ainda.. temos apenas um teste onde FizzBuzz(3) deveria retornar “fizz”… é esse pequeno passo que vamos dar. TDD também tem a ver com ansiedade, e você precisa aprender a controlar a sua.

#!/usr/bin/env python

def FizzBuzz(numero):
if (numero == 3):
return "fizz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

E os testes passaram! :D

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(9) retorna “fizz”

Eu poderia seguir a lista e partir para o FizzBuzz(4) mas ele provavelmente vai passar, mas ao mesmo tempo, entre a dúvida e o teste, fique com o teste:

def test_FizzBuzz_de4(self):
self.assertEqual(FizzBuzz(4), 4)
view raw
gistfile1.py
This Gist brought to you by GitHub.

Ok.. os testes continuam passando, então esse teste não colaborou em nada para o problema.. Vamos dar um pulo e testar nosso caso mais recente:

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_FizzBuzz_de1(self):
self.assertEqual(FizzBuzz(1), 1)

def test_FizzBuzz_de2(self):
self.assertEqual(FizzBuzz(2), 2)

def test_FizzBuzz_de3_retorna_fizz(self):
self.assertEqual(FizzBuzz(3), "fizz")

def test_FizzBuzz_de4(self):
self.assertEqual(FizzBuzz(4), 4)

def test_FizzBuzz_de9_retorna_fizz(self):
self.assertEqual(FizzBuzz(9), "fizz")

if __name__ == '__main__':
unittest.main()

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(9) retorna “fizz”

Ok.. os testes quebraram.. mas como vamos resolver o problema?

Sabemos que nosso código ainda tem um “roubo”, podemos fazer outro roubo ou partir para uma refatoração que resolva o FizzBuzz(3) e FizzBuzz(9), como o problema é ridiculamente simples e esse artigo está ficando longo demais, vamos pra segunda opção:

#!/usr/bin/env python

def FizzBuzz(numero):
if not numero % 3:
return "fizz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

E os testes passaram! :)

Vejam que foi uma refatoração bem simples, ao invés de verificar se o número é igual a três, eu verifiquei se não sobrou resto da sua divisão por três, ou seja: se ele é múltiplo de três.

Uma coisa que está me incomodando um pouco são todos os nomes testes, acho que podemos refatorar o teste a grupar casos semelhantes:

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_numeroSimples(self):
self.assertEqual(FizzBuzz(1), 1)
self.assertEqual(FizzBuzz(2), 2)
self.assertEqual(FizzBuzz(4), 4)

def test_numeroMultiploDeTres(self):
self.assertEqual(FizzBuzz(3), "fizz")
self.assertEqual(FizzBuzz(9), "fizz")

if __name__ == '__main__':
unittest.main()

Agora sim! Bem melhor, e continuamos testando a mesma coisa… só que com menos testes e mais asserções por teste.

Nossa lista está quase acabando…

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(9) retorna “fizz”

Falta apenas o FizzBuzz(5) mas acho que é hora de revisar o problema e adicionar mais alguns itens à lista:

  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(10) retorna “buzz”
  • FizzBuzz(15) retorna “fizzbuzz”
  • FizzBuzz(30) retorna “fizzbuzz”

Claro que eu já sei como o problema funciona, mas podemos levantar esses exemplos só de olhar pra descrição do problema lá em cima..

Então vamos partir pro primeiro item da lista: FizzBuzz(5) retorna “buzz”

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_numeroSimples(self):
self.assertEqual(FizzBuzz(1), 1)
self.assertEqual(FizzBuzz(2), 2)
self.assertEqual(FizzBuzz(4), 4)

def test_numeroMultiploDeTres(self):
self.assertEqual(FizzBuzz(3), "fizz")
self.assertEqual(FizzBuzz(9), "fizz")

def test_numeroMultiploDeCinco(self):
self.assertEqual(FizzBuzz(5), "buzz")

if __name__ == '__main__':
unittest.main()

Os testes voltam a quebrar, apenas o último teste falhou pois 5 != “buzz”.

Como ainda não explicitamos a regra do “multiplo de 5″ através de testes, o correto aqui é fazer com que apenas essse teste passe (e não testes futuros):

#!/usr/bin/env python

def FizzBuzz(numero):
if not numero % 3:
return "fizz"

if numero == 5:
return "buzz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

E todos os testes passaram! :D

Agora vamos colocar mais um múltiplo de cinco, como por exemplo FizzBuzz(10) e o teste vai quebrar:

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_numeroSimples(self):
self.assertEqual(FizzBuzz(1), 1)
self.assertEqual(FizzBuzz(2), 2)
self.assertEqual(FizzBuzz(4), 4)

def test_numeroMultiploDeTres(self):
self.assertEqual(FizzBuzz(3), "fizz")
self.assertEqual(FizzBuzz(9), "fizz")

def test_numeroMultiploDeCinco(self):
self.assertEqual(FizzBuzz(5), "buzz")
self.assertEqual(FizzBuzz(10), "buzz")

if __name__ == '__main__':
unittest.main()

Vamos então parar de roubar e fazer o que fizemos com com os múltiplos de três:

#!/usr/bin/env python

def FizzBuzz(numero):
if not numero % 3:
return "fizz"

if not numero % 5:
return "buzz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

E todos os três testes (com as 7 asserções) passaram novamente.

  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(10) retorna “buzz”
  • FizzBuzz(15) retorna “fizzbuzz”
  • FizzBuzz(30) retorna “fizzbuzz”

Agora vamos atacar a última parte do problema, múltiplos de três e de cinco.

Nada de escrever código, primeiro o teste:

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_numeroSimples(self):
self.assertEqual(FizzBuzz(1), 1)
self.assertEqual(FizzBuzz(2), 2)
self.assertEqual(FizzBuzz(4), 4)

def test_Fizz(self):
self.assertEqual(FizzBuzz(3), "fizz")
self.assertEqual(FizzBuzz(9), "fizz")

def test_Buzz(self):
self.assertEqual(FizzBuzz(5), "buzz")
self.assertEqual(FizzBuzz(10), "buzz")

def test_FizzBuzz(self):
self.assertEqual(FizzBuzz(15), "fizzbuzz")

if __name__ == '__main__':
unittest.main()

(Aproveitei também pra mudar o nome dos testes)

Vejam vocês… o teste falhou.. mas diferente do que vimos até agora, não temos “15 != fizzbuzz” mas sim “fizz != fizzbuzz” pois 15 é multiplo de 3, correto?

$ python fizzbuzz_test.py
..F.
======================================================================
FAIL: test_FizzBuzz (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 22, in test_FizzBuzz
    self.assertEqual(FizzBuzz(15), "fizzbuzz")
AssertionError: 'fizz' != 'fizzbuzz'

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

Primeiro roubamos (o que o Kent Beck chama de “implementação óbvia”):

#!/usr/bin/env python

def FizzBuzz(numero):
if numero == 15:
return "fizzbuzz"

if not numero % 3:
return "fizz"

if not numero % 5:
return "buzz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

E todos os testes voltam a passar… Agora adicionamos mais um teste da nossa lista:

  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(10) retorna “buzz”
  • FizzBuzz(15) retorna “fizzbuzz”
  • FizzBuzz(30) retorna “fizzbuzz”

E fazemos uma implementação simples, que resolva o problema:

#!/usr/bin/env python

def FizzBuzz(numero):
if not numero % 15:
return "fizzbuzz"

if not numero % 3:
return "fizz"

if not numero % 5:
return "buzz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Agora, que todos os testes estão passando e o problema está resolvido, podemos refatorar nossa função pra algo mais elegante:

#!/usr/bin/env python

def MultiploDeTres(numero):
return not numero % 3

def MultiploDeCinco(numero):
return not numero % 5

def FizzBuzz(numero):
if MultiploDeTres(numero) and MultiploDeCinco(numero):
return "fizzbuzz"

if MultiploDeTres(numero):
return "fizz"

if MultiploDeCinco(numero):
return "buzz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Não que essa solução seja a mais elegante e mais eficiente em Python, mas acredito que ela deixe a lógica mais clara.

Enfim… TDD é isso!

Espero que vocês tenham gostado. :D

Deixe um comentário

Envio de email via prompt windows 7

Overview

Em certas circunstâncias temos que testar o envio de e-mail via linha de comando de uma forma básica sem utilizar cliente de e-mail, com isto temos mais agilidade nos testes.

Solução

Para o teste de SMTP devemos utilizar somente o telnet que já vem com o Sistema Operacional.

Devemos ir em Start e depois em Run
E digitar cmd e OK
No prompt devemos digitar telnet 25
Devemos digitar Helo andersonpatricio.org (ou seu domínio que está enviando a mensagem)
Em seguida: mail from: anderson@andersonpatricio.org
Depois: rcpt to: anderson@quattuor.com.br, onde é o e-mail que está residente no servidor que estamos testando, no meu exemplo dei um telnet no servidor mail.quattuor.com.br e estou enviando um teste para anderson@quattuor.com.br
Devemos digitar data e depois para podermos escrever o e-mails, para terminar o corpo da mensagem temos que colocar um “.” em uma linha vazia e dar um
O servidor de e-mail irá dizer que a mensagem ficou na fila para entrega (Queued mail for delivery)
Depois é só digitar um quit para fecharmos o teste de e-mail.

Fonte: http://www.andersonpatricio.org/Tutoriais/AP040_b.html

OBS: Para windows 7 é necessario habilitar o recurso em: Painel de Controle > Programas e Recursos > Ativar ou desativar recursos do Windows > Selecionar Cliente Telnet e clicar em OK

 

Bem, tentei dessa forma, mas para conexão com smtp.gmail.com, ele exige autenticação TLS.

Essa autenticação não é possível com telnet nativo, pensei em usar openSSL, mas um arquivo “bat” não conseguiria enviar todas as informações para envio do email.

Então criei uma applicação console em C#. Foi simples e fácil. Só usando o namespace System.Net consegui o que eu queria.

Veja como ficou:

Class Program:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text;
namespace MgSendEmail {
     class Program
     {
         static int Main(string[] args)
         {
             if (args.Length != 7)
             {
                 Console.WriteLine("Informe os 7 argumentos:");
                 Console.WriteLine("emitente senha destinatario assunto mensagem servidor porta");
                 return 1;
             }
             else
             {
                 SendEmail se = new SendEmail();
                 se.MgSendEmail(args[0], args[1], args[0], args[2], args[3], args[4], args[5], Int32.Parse(args[6]));
                 return 0;
             }
         }
     }
 }

 

Class SendEmail

using System;
 using System.Collections.Generic;
 using System.Linq; using System.Text;
 using System.Net.Mail;
namespace MgSendEmail 
{
     class SendEmail
     {
         public void MgSendEmail(string user, string pass,
         string from, string to,
         string subject, string message,
         string server, int port)
         {
             SmtpClient client = new SmtpClient();
             client.Host = server;
             client.Port = port;
             client.EnableSsl = true;
             System.Net.NetworkCredential nc = new System.Net.NetworkCredential(user, pass);
             client.Credentials = nc;
             MailMessage msg = new MailMessage(from, to, subject, message);
             client.Send(msg);
         }
     }
 }

 

Pronto agora criei um bat que chama a aplicação compilada passando os dados.

,

Deixe um comentário

Investimento do governo em TI para inovação

Ótima noticia que recebemos no começo desse mês: http://blog.planalto.gov.br/com-o-programa-ti-maior-governo-vai-investir-r-500-milhoes-para-a-producao-de-software-no-brasil-diz-dilma/

O governo federal vai investir meio bilhão para a produção de software.

Com certeza, se o governo deseja que a produção científica e tecnológica seja valorizada esse é um começo.

Os estudantes precisam se preparar melhor para conseguir inovar de verdade. Temos tudo a nosso favor (pelo menos a grana está vindo, hehe). Vamos por a mão na massa!

Deixe um comentário

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.