Testando o Twitter com o Watir

No último post, vimos como instalar o Watir e escrever um teste usando ele.

Neste iremos nos aprofundar mais no Watir e para isso nada melhor do que testar.

Após a leitura do post, você estará sabendo:

  • Como modelar os seus testes utilizando orientação a objetos;
  • A importância de utilizar orientação a objetos nos seus testes;
  • Novos métodos da API do Watir;
  • Como fazer asserções de eventos assíncronos (AJAX).

Contexto

A equipe do Twitter ficou sabendo que existe uma comunidade brasileira que manja muito de Teste de Software.  Então, decidiram terceirizar para nós, a automação de alguns testes do Twitter.

Embora a parte da equipe do Twitter ter feito essa solicitação não seja verdade (hehe), somos pró-ativos, não somos?

Nossa missão é testar a funcionalidade de enviar uma mensagem no Twitter, o bom e velho “tweetar”. Os cenários de teste que temos são os seguintes:

  • Enviar uma mensagem válida;
  • Enviar uma mensagem repetida;
  • Enviar uma mensagem com mais de 140 caracteres;
  • Enviar uma mensagem em branco.

Típicos testes de sistema, então vamos colocar a mão na massa!

Como iremos modelar os testes?

Lembra do nosso primeiro teste usando o Watir? Ele é simplesmente um script de teste. Podemos muito bem fazer todos os nossos testes daquela maneira. Porém, vamos usar um pouco a nossa imaginação, para entender como o nosso mundo pode estar, se seguimos essa abordagem.

Temos mais de 100 testes, todos espalhados em scripts de teste, alguns contém só algumas linhas, outros são quase uma dissertação. Todos eles são gerenciados por um script mestre, que chama os scripts de teste e vai armazenando os resultados, para depois “printar” na tela.

Eu chamo o cenário acima de CAOS.

Automatizar os testes dessa maneira, é criar uma bola de neve que só irá aumentar, aumentar e um dia ninguém mais irá consegui movimentar ela. E aí vão culpar a ferramenta que é um lixo, ou a aplicação sob teste, quando na verdade o culpado é a própria equipe, que deu maior importância na criação dos testes, mas que acabou se esquecendo de organizar/estruturar a criação deles.

Além disso, o cenário acima mostra claramente uma reivenção da roda sem nenhuma necessidade: o gerenciamento dos testes. Hoje há muitas ferramentas que podem fazer isso para nós, no ecossistema Ruby, temos o TestUnit e o Rspec, por exemplo.

Uma abordagem mais efetiva, é utilizar orientação a objetos ao modelar os testes. Desta maneira será muito mais fácil dá manutenção no código e reutilizar-lo.

Como iremos aplicar OO nos nossos testes?

Como você sabe (se não sabe, deveria saber – leia esse livro e/ou essa apostila para aprender), a orientação a objetos é uma forma de organizar o nosso código, que nos orienta a trabalhar com objetos (não dá para ficar explicando conceitos de OO neste post, pois ele iria ficar enorme e minha explicação não seria melhor que a do Matt ou do pessoal da Caelum).

No nosso caso, uma página seria um objeto. Faz sentido não faz? Afinal, uma página contém atributos (os elementos HTML) e ações (as funcionalidades que ela provê).

Todos os nossos testes sehrão feitos numa mesma página, a página home do Twitter , portanto iremos instanciar o objeto HomePage da classe HomePage.

A primeira versão da nossa classe HomePage contém os seguintes métodos:

  • visit – acessa a home page do Twitter (twitter.com);
  • login – fará login no Twitter;
  • type_message – digita uma mensagem;
  • tweet – clica no botão para enviar uma mensagem;
  • message_exists? – verifica se uma mensagem existe na timeline;
  • alert_message_exists? – verifica se uma mensagem existe na página;
  • tweet_button_is_disable? – verifica se o botão para enviar a mensagem está desabilitado.

Falta alguma coisa, não falta não?

Os atributos da nossa classe.

Isso mesmo, mas vamos deixar eles de lado no momento, para não complicar demais o entendimento do nosso exemplo, afinal estamos começando, então vamos com calma e deixar eles para uma refatoração em um futuro post.

Você irá notar que, ao invés, de interagir com os atributos da classe HomePage, os nossos métodos estão usando o objeto browser para lidar com os elementos da página. Ou seja, abstrair os atributos da home page do Twitter, é luxo para a nossa primeira versão.

Testando o Twitter

Vamos parar com o blá-blá e ir para o código. Primeiro a classe que iremos utilizar nos nossos testes:

require 'rubygems'
require 'watir'
#require 'firewatir' => se você estiver no Linux/Mac

class HomePage

  HOME_PAGE = 'twitter.com'

  def initialize
    @browser = Watir::Browser.new
  end

  def visit
    @browser.goto(HOME_PAGE)
  end

  def login(username, password)
    @browser.text_field(:name, 'session[username_or_email]').value = username
    @browser.text_field(:name, 'session[password]').value = password
    @browser.button(:class, 'submit button').click
  end

  def type_message(message)
    @browser.text_field(:class, 'twitter-anywhere-tweet-box-editor').value = message
    @browser.text_field(:class, 'twitter-anywhere-tweet-box-editor').fire_event("onMouseDown")
  end

  def tweet
    @browser.link(:class, "tweet-button button").click
  end

  def message_exists?(message)
    @browser.wait_until {@browser.div(:class, 'tweet-text').text == message}
  end

  def alert_message_exists?(message)
    @browser.wait_until {@browser.text.include? message}
  end

  def tweet_button_is_disabled?
    @browser.link(:class, "tweet-button button disabled").exists?
  end

end

Aí está a nossa classe bonitona. Nela conseguimos abstrai várias ações que podemos fazer na página home do Twitter, desde preenchimentos até verificações de elementos.

Antes de irmos para os nossos testes propriamente ditos, vamos dá uma olhada nos métodos da API do Watir que estamos usando pela primeira vez:

  • @browser.text_field(:class,  ‘twitter-anywhere-tweet-box-editor’).value – no nosso primeiro teste usamos o set para preencher o text_field, agora estamos usando o value, simplesmente porque o set tem um bug no Firewatir (se você está testando usando o IE, e assim usando o Watir e não o Firewatir, não terá esse problema), e uma das formas de contornar ele, é usar o value;
  • @browser.text_field(:class,  ‘twitter-anywhere-tweet-box-editor’).fire_event(“onMouseDown”) –  o fire_event possibilita disparar um evento num elemento. No caso nosso seria como se a pessoa estivesse com o mouse em cima do text_field para digitar a mensagem e clica nele. Precisamos fazer isso, pois só assim o botão (que na verdade é um link) para “tweetar” será habilitado, uma vez que ele depende do disparo desse evento Javascript;
  • @browser.wait_until – o Watir é bem espertinho quanto a espera para carregar a página, esperando realmente ela carregar, e assim não precisamos ficar doidos adicionando sleeps. Porém ele não é mágico e com o wait_until podemos esperar a nossa mensagem aparecer na timeline, tendo ele um timeout de 60 segundos, o que é muito bom, pois não queremos esperar infinitamente. Estamos usando ele, pois a nossa mensagem aparece na timeline de forma assíncrona (AJAX), ou seja, a página não é carregada novamente, e então não podemos utilizar um @browser.text.included?(‘nossa mensagem’);
  • @browser.link(:class, “tweet-button button disabled”).exists? – este método é auto-explicativo, ele verifica se o elemento existe ou não na página. Estamos usando ele, pois a forma de descobrir se o link para “tweetar” a mensagem está habilitado ou não, é através da classe css do link, que quando desabilitado também terá a classe disabled.

Feitas as devidas explicações, vamos vê como ficam os nossos testes utilizando a classe HomePage:

USERNAME = 'SEU USUÁRIO NO TWITTER'
PASSWORD = 'A SUA SENHA NO TWITTER'
MESSAGE = 'testando o Twitter'

MESSAGE_WITH_MORE_THAN_140_CARACTERS = 'testando o limite de caracteres na mensagem no  Twitter, chegou? ainda nao? nao? nao? ainda nao? quando vamos chegar? estamos perto? chegamos!'

TWITTER_REPEATED_MESSAGE = 'Whoops! You already said that...'

#Teste 1 - Enviar uma mensagem válida

home_page = HomePage.new
home_page.visit
home_page.login(USERNAME,PASSWORD)
home_page.type_message(MESSAGE)
home_page.tweet

message = 'O teste enviar uma mensagem válida'
if home_page.message_exists? MESSAGE
 puts "#{message} PASSOU"
else
 puts "#{message} FALHOU"
end

#Teste 2 - Enviar uma mensagem repetida

home_page.type_message(MESSAGE)
home_page.tweet

message = 'O teste enviar uma mensagem repetida'
if home_page.alert_message_exists? TWITTER_REPEATED_MESSAGE
 puts "#{message} PASSOU"
else
 puts "#{message} FALHOU"
end

#Teste 3 - Enviar uma mensagem com mais de 140 caracteres

home_page.type_message(MESSAGE_WITH_MORE_THAN_140_CARACTERS)

message = 'O teste enviar uma mensagem com mais de 140 caracteres'
if home_page.tweet_button_is_disabled?
 puts "#{message} PASSOU"
else
 puts "#{message} FALHOU"
end

#Teste 4 - Enviar uma mensagem em branco

home_page.type_message('')

message = 'O teste enviar uma mensagem em branco'
if home_page.tweet_button_is_disabled?
 puts "#{message} PASSOU"
else
 puts "#{message} FALHOU"
end

Com certeza os nossos testes ficaram bem melhor utilizando a classe HomePage, em comparação se a gente fosse fazer sem ela. No entanto, eles estão BEM RUINS, em comparação com os testes do próximo post. 😀

A intenção dos posts não é dá “a melhor” solução de bandeja, afinal o melhor da jornada da automação dos testes (e de qualquer outra jornada), é justamente o caminho, se eu mostrasse logo no primeiro post a solução final, a gente não ia entender os motivos pelos quais ela é uma solução melhor que as anteriores. Talvez até seria possível entender, mas evoluindo aos poucos, irá ficar muito mais clara a diferença desses testes porcos, para os da solução final.

De qualquer modo, já atendemos a demanda que foi solicitada pelo pessoal do Twitter (hehe). O que iremos vê no próximo post, será como melhorar o código dos nossos testes, utilizando o Rspec. Até lá!

Observações

  • Disponibilizei no meu Gist, o código completo do post: http://bit.ly/ges0xH
  • O código foi testado no Windows com o IE8 e também no Ubuntu usando o Firefox 3.6 (lembrando que para testar usando o Firefox, você tem que usar o firewatir e não o watir).

Saiba mais

Para saber mais sobre o Watir, acesse o meu delicious, lá estou guardando vários links a respeito do Watir, e não deixe de visitar a página oficial do projeto, lá tem vários bons exemplos e explicações.

Fique por dentro das novidades, assine o feed do QualidadeBR.

Conheça o Watir

O objetivo deste post é fazer uma introdução a ferramenta Watir (mesma pronúncia de water). Como sendo uma introdução, irei abordar o básico do básico, até porque a minha experiência com o Watir são de menos de 1 hora.

Ao terminar a leitura deste post, você estará sabendo:

  • O que é o Watir
  • Porquê usar o Watir
  • Como instalar o Watir
  • Realizar um teste básico com o Watir

O que é o Watir?

Primeiro a resposta curta de quem não conhece muito: Um Selenium desenvolvido em Ruby, cujo seus testes também serão escritos em Ruby.

Agora uma resposta apoiada no conteúdo da página oficial do Watir: O Watir é uma ferramenta para você testar aplicações Web, sob a licença BSD. Ela é um conjunto de bibliotecas em Ruby que permite você automatizar os seus testes. Você escreve os seus testes em Ruby e pode rodá-los no IE, Firefox, Chrome, Safari e Opera.

Ou seja, a minha primeira resposta é válida, porém está longe de ser a mais completa. No entanto, de início vamos com ela, afinal só iremos ter uma melhor resposta usando o Watir. 🙂

Por que usar o Watir?

Os motivos para usar o Watir são [1]:

  • É uma ferramenta open source e não há custos para usar;
  • A comunidade do Watir está crescendo e é muita ativa;
  • Ele usa Ruby, uma linguagem de script moderna e completa e que possui uma baixa curva de aprendizado (em comparação com Java, por exemplo);
  • Ele suporta qualquer aplicação web, não importando a linguagem na qual ela foi desenvolvida;
  • O Watir suporta múltiplos browsers e diferentes plataformas;
  • Ele é poderoso, fácil de usar e ainda é bem leve.

Como instalar o Watir

Para instalar o Watir o único pré-requisito é ter instalado o Ruby (versão 1.8.6 ou 1.8.7). Portanto vamos instalar, lembrando que os próximos passos foram feitos no Windows (se você usa Linux, vá no tópico Instalando no Linux):

  1. Instale o Ruby 1.8.7-p334 (saiba mais em RubyInstaller);
  2. Ao iniciar a instalação, logo após aceitar os termos, marque os dois checkboxes (“Add Ruby executables to your PATH” e “Associate .rb and .rbw files with this Ruby installation”) e clique em Install;
  3. Ao terminar a instalação, vá no prompt de comando (ctrl+r e depois digite cmd) e digite os seguintes comandos:
    • ruby -v (deverá retornar a versão do Ruby que foi instalada, ex: ruby 1.8.7)
    • gem -v (deverá retornar a versão do RubyGems que foi instalada, ex: 1.5.2)
    • irb (deverá entrar no irb – o shell interativo do Ruby), dentro dele escreva:
      • puts “hello world”
    • depois digite exit para sair do irb.

Se tudo deu certo, parabéns o Ruby foi corretamente instalado e de quebra você escreveu um Hello World em Ruby. 😉

Agora vamos instalar o Watir:

  1. No prompt do Windows digite: gem install watir

Pronto só isso, se nenhum erro ocorreu, já temos o Watir instalado. Caso algum erro tenha ocorrido, consulte o último tópico Erros comuns.

Realizando um teste com o Watir

Segue abaixo, um screencast mostrando como realizar um teste simples com o Watir (assistir em 720p é recomendado). Estarei fazendo o teste usando o irb:

O teste executado foi baseado no exemplo do site oficial do Watir, para vê outros exemplos acesse essa página.

Você pode fazer o mesmo teste na sua máquina, de duas formas:

  • Pelo irb, como fiz no vídeo, informando cada “comando” no irb;
  • Ou de uma forma mais fácil, baixando esse arquivo, que contém todo o script de teste completo. Além dos código que foi informado no irb, tem também vários comandos e puts, para facilitar o entendimento do código. Lembrando que após baixar o arquivo, é só executar o watir_example.rb, que um prompt abrirá e nele serão “printados” os passos e também o resultado do teste.

Conclusão

Como pudemos ver no vídeo, o Watir interage diretamente com o browser. Nós só precisamos conhecer a API dele, para podermos criar os nossos próprios testes, e é claro também um pouco de Ruby irá ajudar.

Resumindo, o que precisamos saber para criar o nosso próprio teste usando o Watir é o seguinte:

  • O valor da propriedade name dos elementos que iremos ter que interagir para poder fazer os passos do nosso teste (o desenvolvedor pode passar essa informação para você, ou você pode encontrar usando o Firebug);
    • Numa rápida pesquisa, parece que existem IDEs de record-play (estilo o Selenium IDE) para o Watir, porém nenhuma é mantida oficialmente.
  • A API do Watir, basicamente conhecer quais são os métodos que podemos usar, quando usar e quais parâmetros passar;
  • A linguagem Ruby, mas calma não precisa aprender toda a linguagem de uma vez, vá com calma, comece primeiro com exemplos básicos (como esse que mostrei) e vá incrementando eles.

Bem é isso. Qualquer dúvida, crítica ou sugestão, sintam-se à vontade em deixar nos comentários.

Instalando no Linux

Para instalar o Ruby, Rubygems e Watir no Linux, preparei um script (testado no Ubuntu). Basta baixar ele, alterar a permisão (chmod +x watir_installation.sh) e rodar o script com sudo (sudo ./watir_installation.sh).

Uma coisa que muda no script do teste, é que ao invés, de fazer o require no watir, você irá fazer o require no firewatir (require firewatir), que é o driver para o Firefox. Além disso, você terá que instalar esse plugin no Firefox. Maiores detalhes, é só conferir o procedimento de instalação que está disponível no site do Watir (lá tem para quem usa Mac também).

Erros comuns

Erro: ERROR:  While executing gem … (Errno::ENXIO)

Solução:

  • Vá no diretório C:\Ruby187\bin (ou no local que você especificou para instalar o Ruby na sua instalação);
  • Faça uma cópia do arquivo gem (para fazer backup);
  • Edite esse mesmo arquivo (gem), alterando o seu conteúdo para o que está aqui.

Fique por dentro das novidades, assine o feed do QualidadeBR.

Fonte:

[1] http://watir.com/

6º Encontro do Guru-SP – Eu fui!

Em pleno sabadão, num dia lindo acordo antes das 07:00, e não é para ir para a praia ou coisa do tipo, e sim para ir ao 6º Encontro do Guru-SP. 😀

Mas que “diacho” de encontro é esse Fabrício? Você foi consultar um guru espiritual?

Guru Ram Das, o 4º Guru da religião Sikh

Não, não (rsrs). O Guru-SP é esse daqui:

GURU SP

Hmmm… agora entendi. Mas o que você foi fazer num encontro de usuários de Ruby? Você programa em Ruby?

Não (mas depois de hoje fiquei com mais vontade ainda de aprender).

Um dos motivos para ter ido ao encontro foi o tema “Testes Automatizados” dele. Não tem jeito, colocar a palavra “teste” no tema de um evento, é mais efetivo do que falar que vai ter coffee break, para me fazer participar.

rsrs… que atitude nerd, perder um dia lindo desse, para ir num evento só por causa que vai falar sobre testes.

Que isso, olha o preconceito. Não é todo dia que você tem a oportunidade de participar de um evento sobre testes, onde que ia falar não atua na área de Teste de Software ou QA, e sim o pessoal do “lado negro da força” (“brincadeira minha, não é falando mal!”).

Interessante mesmo! Quem organizou o evento?

O 6º Encontro do Guro-SP foi organizado pelo Rafael Rosa, com o apoio da GoNow (local do encontro), Voice Technology (empresa na qual trabalho), O’Reilly e Ruby Inside Brasil, além é claro do Grupo de Usuário Ruby de SP.

E como foi o formato do encontro?

Foi no formato de mesa redonda (muito bom!), o pessoal da mesa ia falando sobre vários temas, que foram votados antes pelo pessoal que participou do encontro. Os debatedores foram:

  • Anderson Leite
  • Cássio Marques
  • Diego Carrion (não pode comparecer)
  • Fabio Kung (não pode comparecer)
  • Jorge Diz (o Jorge será o palestrante do 6º Encontro Mensal da ALATS-SP, a ser realizado nessa quarta-feira)
  • Ricardo Yasuda
  • Thiago Scalone

E o encontro foi dividido em duas partes, a primeira estimado das 10:00 ao 12:00 e a segunda das 12:30 às 15:00.

Da hora, a primeira parte como foi?

Ela começou com quase uma hora de atraso, com o Rafael Rosa falando sobre o encontro e como seria feito esse. Logo após, o pessoal já começou a “descer a lenha” falando sobre “Por que testar”, e pude perceber que a galera é bem comprometida como a realização dos testes, eles levam a sério mesmo e entendem as razões de porque testar.

Os debatedores também contaram experiências que tiveram fazendo BDD com o Cucumber e realizando testes de interface com o Selenium, por exemplo. Esse foi um ponto muito positivo do evento, ficou claro que os debatedores fazem o que eles falam, e puderam compartilhar experiências bem interessantes com o público. E a interação do público foi muito boa também, várias pessoas contaram os cenários que vivem, e também algumas dificuldades que tem em realizar os testes:

  • Tempo: projetos com prazos para ontem. Na minha opinião, realizar testes, principalmente na fase de desenvolvimento é uma prática que gera efeitos não tão bons a curto prazo, mas que a médio e longo prazo, se mostra essencial! Porém, como vivemos numa geração imediatista, muitas vezes as pessoas tem dificuldade em entender isso.
  • Complexidade: a criação de testes em sistemas complexos é um desafio maior ainda, às vezes pode ser mais difícil do que a própria implementação.
  • Sistemas legados: se dá uma manutenção em um sistema legado já é uma missão de embrulhar o estômago, imagine só criar testes para ele. Uma solução legal, comentada pelo pessoal e colocada em prática é realizar testes em nível de sistema, utilizando o Selenium por exemplo.

O Jorge Diz lembrou que a área de Teste de Software, costuma vir no reboque quando se usa metodologias frágeis (tradicionais). Mas usando metodologias ágeis o Teste de Software é incentivado, as novas técnicas já trazem na sua essência o pensamento de testar. Aliás, um exemplo disso é o uso de programação em par, onde uma pessoa já está revisando o código (lembrando que revisar é uma forma de testar).

Sobre o uso de BDD e TDD, o Anderson Leite disse que antes de partir para o uso delas, as pessoas precisam primeiro adquirir o hábito e prática de testar, só depois que já tiverem maduras podem começar a usar o BDD e TDD.

O Cássio Marques contou um pouco da sua experiência com linguagens de comparação, comparando no quesito de facilidade de testar. E disse que escrever testes em C e C++ é bem difícil, em Java também é meio enrolado. Já em Ruby é bem mais fácil. Podemos dizer que Ruby tem uma melhor “testabilidade”, que as outras, ou seja, se você é desenvolvedor Ruby e não testa, então você tem uma desculpa a menos para usar. 🙂

Um ponto importante discutido foi que se você testa, você não pode se dar ao luxo de deixar de testar uma funcionalidade, pois poderá resultar na velha história da janela quebrada.

Para terminar a primeira parte, houve uma demonstração do uso do Cucumber pelo Anderson. A minha primeira impressão foi que pareceu mágica o que ele fez (rsrs), ele escreveu os testes usando TDD e gerou o código usando o Scaffold de um cadastro de participante que tinha os campos nome e e-mail. Achei bem legal a demonstração, o Cucumber é uma ferramenta muito legal, nela você cria o teste como se estivesse criando uma caso de teste, segue abaixo um exemplo:

Exemplo de teste feito para o Cucumber

O Cucumber utiliza por default o Webrat, porém também é possível realizar o teste usando o Selenium RC, basta passar como parâmetro. O interessante do uso do Webrat é que diferente do Selenium, ele simula o navegador, rodando em background, ou seja, é muito mais rápido que o Selenium RC, porém tem a limitação de não conseguir testar javascript.

E depois do “rango”,  a segunda parte foi no mesmo nível que a primeira?

Depois do excelente coffee break, o Jorge Diz passou vários slides explicando a teoria de testes, abordando desde as escolas de teste até sobre os tipos de dublês. Essa parte fugiu um pouco do formato de debate, mas logo o Rafael Rosa retomou o formato, estimulando uma discussão sobre mocks e o perigo de “engessar muito” utilizando eles.

Do debate sobre mocks, o pessoal chegou a seguintes conclusões:

  • Se você está “mockando” muito, pode ser um sinal que a sua classe está fazendo mais do que ela deveria fazer. Então REFATORE;
  • Sempre tente modularizar ao máximo a sua aplicação, nada de ter uma classe “sistema”;
  • Os dublês em geral, devem ser usados sempre para resolver uma dependência.

Um assunto interessante abordado na apresentação do Jorge, foi como deve ser a pirâmide dos testes, de acordo com o nível:

TestingPyramidMas o que ocorre, geralmente, sem essa cultura de que desenvolvedor também testar, é uma inversão dessa pirâmide, ou seja, não há quase nenhum teste de unidade e integrado realizado, e muitos testes de sistema feitos pelo pessoal de Teste de Software.

E ainda houve mais duas práticas, uma com o Thiago Scalone mostrando o Selenium IDE e o RC. E depois mais uma com o Anderson apresentando o RSpec (o JUnit do Ruby)

E o que você achou? Pelo jeito deve ter sido ótimo, afinal além de falar de testes deve coffee break na faixa.

Excelente encontro! Comprovou que é mito essa história que desenvolvedor não testa, eles testam sim, e até melhor do que muito testador que tem por aí. E Ruby é uma linguagem que oferece uma “testabilidade” incrível, as ferramentas que existem são muito boas, e ajudam desde o teste de nível unitário até o teste de nível de aceite. E essa brincadeira que faço sobre “lado negro da força”, em breve ficará sem sentido, pois os testes estão se tornando cada vez mais uma tarefa inerente ao desenvolvimento.

Para encerrar o post, parabéns a todos que participaram, e principalmente, ao Rafael Rosa, pela excelente organização!

Para saber mais sobre o 6ºEncontro acesse a wiki do Guru-SP:

http://guru-sp.com/index.php/Sexto_Encontro

E para saber sobre os próximos encontros acompanhe o Ruby Inside Brasil:

http://www.rubyinside.com.br/

Fique por dentro das novidades, assine o feed do QualidadeBR.

guru espiritual