Blog da Improve It

Como Testar parte 1 - Models

Publicado por Marcos Tapajós há mais de 6 anos.

Quando comecei a estudar [Extreme Programming][xp] descobri que não é possível fazer nenhum software de qualidade sem uma excelente base de testes. Desde então tenho me dedicado muito ao estudo das mais diversas ferramentas e técnicas para elaborar bons de testes. O assunto testes é bastante polêmico e não pretendo (nesse post) tentar convencer ninguém da importância deles. Se você não faz testes e/ou discorda de qualquer uma das minhas afirmações deixo algumas perguntas para você refletir. 1 - Quantos bugs fixes você fez esse ano? 2 - Quantos tickets abertos existem no seu bug tracker? 3 - Quantas vezes você fez um deploy de uma nova versão em uma sexta feira de tarde e saiu mais cedo do trabalho? 4 - Quantas vezes você "virou a noite" esse ano? Acabei me tornando um evangelizador de testes porém nunca fiz nada muito prático para passar o conhecimento que eu adquiri para a comunidade. Só que agora vou me redimir dessa falha iniciando uma série de posts onde vou expor um problema e como EU testaria usando Test::Unit e Rspec. Não vou falar de Shoulda pois não gosto dele. :-) A idéia de escrever essa série de posts sobre testes surgiu logo após a gravação do terceiro episódio do [RailsBox][rb] e gostaria de agradecer ao Ozeias e ao Davis Cabral por terem me motivado. "Back to the cold cow..." O ActiveRecord simplifica muito nossos modelos porém tenho observado que em vários projetos os desenvolvedores deixam de testar corretamente os seus modelos usando a alegação que não vão testar alguma coisa que o Rails já testou. Esse é um argumento valido em alguns casos pois você está apenas delegando responsabilidades mas você sempre deve testar se a responsabilidade foi realmente delegada. Um exemplo clássico são as validações. Teoricamente você não precisaria testar como elas são implementadas mas deve testar se elas realmente existem pois se alguém remove-las seus testes vão continuar passando mas sua aplicação estará quebrada e/ou permitindo inconsistências de banco de dados. Nesse post vou mostrar como testar alguns comportamento do ActiveRecord usando como base o modelo User. Todos os códigos citados nesse post fazem parte de um projeto How Test que está disponível em: http://github.com/tapajos/how-test class User < ActiveRecord::Base validates_presence_of :name validates_format_of :mail, :with => /([-\.\w^@]+@(?:[-\w]+\.)+[A-Za-z]{2,4})+/i, :on => :create, :allow_nil => true has_many :accounts named_scope :actives, :conditions => ["active = ?", true] end Uma boa estratégia para orientar o desenvolvimento dos teste é elaborar algumas perguntas que darão origem aos seus cenários de testes. ### Validação do nome 1. Posso cadastrar um usuário sem nome? Não #### Testando usando Test:Unit: def test_if_check_presence_of_name assert !@user.valid?, "Should be invalid" assert_equal "can't be blank", @user.errors[:name] end Na primeira linha desse teste o assert recebe um segundo parâmetro que por ser opcional não é muito comentado mas merece uma atenção especial. Esse argumento nada mais é do que a mensagem que será exibida quando o teste quebrar. Quando você omite esse parâmetro o teste quebra exibindo a mensagem 'false is not true' que não ajuda muito a entender o que está acontecendo. #### Testando usando RSpec: it "should reject if name is not given" do @user.should have(1).error_on(:name) @user.errors[:name].should == "can't be blank" end ### Validação do e-mail. 1. Posso criar um registro com um e-mail inválido? Não 2. Posso atualizar um regitro com um e-mail inválido? Sim 3. Posso criar um registro com um e-mail em branco? Sim #### Testando usando Test:Unit: VALIDS_MAIL = %w(foo@bar.com foo@bar.com.br foo@globo.com foo@i_hate_the_microsoft.com foo@i_love_my_mac.com) INVALIDS_MAIL = %w(foobar.com foo@bar i_hate_the_microsoft.com i_love_my_mac.com) def test_if_reject_invalid_format_os_mail_on_create INVALIDS_MAIL.each do |mail| @user.mail = mail assert !@user.valid?, "Should be invalid when mail is #{mail}" assert_equal "is invalid", @user.errors[:mail] end end def test_if_not_reject_when_mail_is_nil @user.name = "Tapajós" assert @user.valid?, "Should be valid" end def test_if_not_check_format_of_mail_on_update @user.name = "Tapajós" assert @user.save, "Should save" @user.mail = "an invalid mail" assert @user.valid?, "Should be valid" end def test_if_accept_a_valid_mail VALIDS_MAIL.each do |mail| @user.name = "Tapajós" @user.mail = mail assert @user.valid?, "Should be valid when mail is #{mail}" end end #### Testando usando RSpec: INVALIDS_MAIL.each do |mail| it "should reject because #{mail} is an invalid mail" do @user.mail = mail @user.should have(1).error_on(:mail) @user.errors[:mail].should == "is invalid" end end VALIDS_MAIL.each do |mail| it "should be valid when mail is #{mail}" do @user.mail = mail @user.should_not have(1).error_on(:mail) end end it "should not reject if mail is not given" do @user.name = "Tapajós" @user.should be_valid end it "should not check mail format on update" do @user.name = "Tapajós" @user.save.should be_true @user.mail = "an invalid mail" @user.should be_valid end ### Testando o relacionamento com Account. 1. Um usuário pode ter mais de uma conta? Sim #### Testando usando Test::Unit: def test_has_many_accounts association = User.reflect_on_association(:accounts) assert association, "Association with account is not found" assert_equal :has_many, association.macro end #### Testando usando RSpec: it "should has many accounts" do association = User.reflect_on_association(:accounts) association.should_not be_nil association.macro.should == :has_many end ### Testando o User.actives 1. Posso listar usuários inativos? Não #### Testando usando Test::Unit: def test_if_actives_use_the_correct_conditions assert_equal({:conditions=>["active = ?", true]}, User.actives.proxy_options) end #### Testando usando RSpec: it "should find for all users that status of active is true" do User.actives.proxy_options.should == {:conditions=>["active = ?", true]} end Para esse post ficar mais simples e curto não me preocupei em validar se o tamanho máximo dos campos está coerente com o tamanho máximo permitido pelo tipo no banco de dados. Essa é uma validação EXTREMAMENTE importante que não deve ser esquecida! No próximo post dessa série falarei um pouco sobre a [Lei de Demeter][ld], como respeita-la e testar alguns métodos usando [Mock Objects][m]. O que você achou desse artigo? O que você gostaria de saber sobre testes de ActiveRecord que eu não falei aqui? Aguardo o feedback de vocês. [m]: http://en.wikipedia.org/wiki/Mock_Object [rb]: http://railsbox.org/2008/9/9/railsbox-podcast-3 [xp]: http://www.improveit.com.br/xp [ld]: http://en.wikipedia.org/wiki/Law_of_Demeter

Tags , , , , , ,  | 46 comentários

O que você achou? Coloque seus comentários e sugestões abaixo!

Acompanhe o RSS dessa página.

Comentários (46 até o momento)

  1. Pedro Pimentel disse aproximadamente 7 horas depois:

    Muito bom o material !!! Parabéns !! Ficou excelente! =D
  2. Elomar França disse aproximadamente 8 horas depois:

    Ótimo artigo, Tapajós. Uma coisa que eu achei interessante foi sua abordagem testando as associações e os named scopes, testando se o Rails fez o que devia fazer (criou a associação e as condições). Eu tô começando agora a testar, ainda aprendendo, e usava uma abordagem diferente pra esse tipo de coisa, baseado nos tutoriais que tinha lido, usando fixtures e testando se elas estão associadas direitinho. O que tu acha dessa abordagem? Tirando o trabalho extra com fixtures, testar o fim (objetos associados) não é mais recomendado que testar o meio (Rails criar as associações)? =)
  3. Eduardo Fiorezi disse aproximadamente 9 horas depois:

    Eita,, bacana o post,, eu não conhecia o reflect_on_association.... Perfeito!!! Abraços
  4. Alberto Leal disse aproximadamente 10 horas depois:

    Tapajós, muito bom o artigo. Comecei na semana passada a estudar testes no ruby e comecei pelo rspec, tô achando mto bacana. Já estou ansioso pelo próximo post!! Abraços, Alberto
  5. Diego Carrion disse aproximadamente 11 horas depois:

    Tapajos, acho que somente deveria existir uma assertion ou expectation por teste. Desse modo eles ficam mais simples de manter e obriga a descrever melhor eles, o que ajuda na hora de querer saber onde esta dando problema a aplicacao. Eu comecei a seguir essa abordagem depois de ler esse post do Jay Fields : http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html []s
  6. Tapajós disse aproximadamente 17 horas depois:

    Elomar, Eu não gosto muito da abordagem de usar fixtures nesse tipo de teste. Acredito que fixtures são bastante úteis em testes de aceitação(Selenium) e no testes funcionais mas tem testes unitários nem tanto. Acredito que você esteja estudando testes com Test:Unit e por isso tem encontrado bastante literatura usando fixtures. Os testes com RSpec desencorajam você a usar fixtures. Você comentou sobre a dúvida entre testar o resultado final ou o meio. Essa é uma dúvida comum e que a explicação está em conhecer os tipos de teste existentes. Existem os chamados testes de caixa preta, onde você fornece uma entrada e quer conferir o resultado final sem se importar em como as coisas são feitas. Em oposição a esses testes existe uma outra categoria onde se tem conhecimento de como as coisas são implementadas e o teste leva isso em conta. Geralmente essas duas categorias de testes acabam gerando a divisão entre testes de unidade e testes funcionais. No caso do exemplo estou me preocupando apenas com a classe User e não estou testando a integração entre os objetos e por isso acho que testes unitários se aplicam melhor. Mas prefiro não me prender a essa "regra" e usar um pouco do bom senso e da minha experiência fazendo testes. Eu acredito que existem alguns conceitos básicos que são importantes mas discordo das afirmações que existe uma forma certa de testar. Acho que o importante é você testar toda a sua aplicação analisando o que é mais proveitoso em cada caso. Normalmente tenho a tendência a testar as responsabilidades me isolando ao máximo das outras camadas e recursos externos, por isso mesmo tenho fugido do uso de banco de dados e fixtures. Resumindo, acho que a resposta para a sua pergunta é depende de que tipo de teste você quer fazer. Será que consegui me fazer claro?
  7. Tapajós disse aproximadamente 17 horas depois:

    Eduardo, eu também só conheci isso faz pouco tempo.
  8. Tapajós disse aproximadamente 18 horas depois:

    Diego, Eu não concordo muito com essa regra de ter apenas um assert por teste desde que esses asserts façam algum sentido. Tome por exemplo o seguinte teste: def test_if_check_presence_of_name assert !@user.valid?, "Should be invalid" assert_equal "can't be blank", @user.errors[:name] end Nesse teste eu faço duas validações e é claro que eu poderia usar apenas a segunda mas a primeira não me parece prejudicar em nada o entendimento do teste. Acho que a grande questão é separar bem as responsabilidades do seus testes e a afirmação do Jay Fields pode fazer algum sentido como uma orientação para se chegar a esse objetivo mas não deve ser seguido como uma regra. Agora se você for olhar o exemplo do PhoneNumber acho que ele foi bastante infeliz pois defende a idéia dele baseado em um teste muito mal feito, onde se mistura as responsabilidades para só então chegar nos testes que deveriam ter sido feito desde o início. Acho que ele deveria ter escrito um teste com dois asserts que fazem sentido e então argumentar em cima disso. Ou então escrever um artigo explicando que bons testes devem se ater a uma única responsabilidade bem definida e, quem sabe, usar a idéia de um assert por teste como uma forma de orientação na hora de elaborar os testes. Acredito que é possível provar qualquer coisa quando se escolhe um exemplo favorável e na minha opinião foi isso que ele fez. Alias, após assistir a apresentação dele na Rails Summit posso dizer que discordo MUITO dele em vários aspectos e não tomaria ele como a única referência sobre testes.
  9. Diego Carrion disse aproximadamente 19 horas depois:

    Oi Tapajos. Para ser sincero, eu nao cheguei a ver os exemplos que ele deu, somente li rapidamente o texto e com isso acho que consegui captar e ideia e me convencer, mas pode ser que tenha deixado pasar algo importante, vou dar outra olhada. Mas voltando ao exemplo que voce deu, me parece que o nome nao reflete o comportamento do teste. No teste voce esta testando se o usuario é considerado invalido e se a mensagem dada é a esperada. Pelo nome do teste somente deveria ser verificado se o usuario é considerado invalido. Isso dos nomes me parece importante porque imaginemos que amanha um membro do time troque o "can't be blank" por "cant be blank". Nesse caso o teste "test_if_check_presence_of_name" nao ira passar, mas na verdade a aplicacao sim esta verificando a presença do nome, o que esta errado é que a mensagem nao é a esperada.
  10. Tapajós disse aproximadamente 19 horas depois:

    Diego, você está certíssimo pois o nome do meu teste está realmente ruim. Não reflete exatamente o que eu gostaria de testar. Por isso eu odeio bolar exemplos... :-)
  11. dookie disse aproximadamente 22 horas depois:

    Acho que além de mostrar testes no Rails você poderia ensinar como fazer testes para Ruby puro. Tá certo que é praticamente igual, mudam alguns requires, mas será que as pessoas que lêem esse post já fizeram testes fora do Rails? []s
  12. Lucas Fais disse 1 dia depois:

    Muito bom o post! Estou começando com testes em Rails. Pesquisando, já me deparei com diversas opiniões diferentes, de alguns caras que têm alguma experiência. Procurando entender esses caras experientes (um deles é você), vou fazer uma pergunta (acredito que você não queria que alguém fizesse): Na sua opinião, porque RSpec é melhor que Shoulda? O que te faz não gostar de Shoulda? Valeu
  13. Jony dos Santos Kostetzer disse 1 dia depois:

    wow, bacana o artigo Tapajós! Que venham os próximos. Também não conhecia o reflect_on_association, interessante. Abraço!
  14. Tapajós disse 1 dia depois:

    Dookie, Farei alguma coisa sobre isso sim.
  15. Tapajós disse 1 dia depois:

    Lucas, Eles são conceitualmente diferentes. Não gosto do Shoulda pois ele tenta imitar um BDD sem ser. Não seria mais fácil usar o BDD ao invés de fazer algo que está no meio do caminho? Se você quiser entender melhor as diferenças dá uma lida nesse [excelente post to Jony][j]. [j]: http://jonysk.net/blog/2008/08/17/shoulda-x-rspec-cuidado-nas-comparacoes
  16. Pablo disse 1 dia depois:

    Muito bom! Parabéns! Já está no Favoritos ;-)
  17. Thiago Pradi disse 1 dia depois:

    Excelente post! Parabéns! Me deu uma grande ajuda, principalmente para testar relacionamentos... Abraço!
  18. Tino Gomes disse 1 dia depois:

    Tápa, Você é feio, bobo e tem cara de mamão! Pronto, já fiz minha contribuição. kkkkkkk Abraços!
  19. AkitaOnRails disse 1 dia depois:

    Grande Tapa! Primeiro, foi mal, quando vi no Google Reader acabei comentando lá como se fosse o Vinicius que tivesse escrito. My bad! Aproveitando o assunto, em sabendo que você também não gosta de fixtures, o que acha dos approaches como "Factory Girl":http://giantrobots.thoughtbot.com/2008/6/6/waiting-for-a-factory-girl e "Object Mother":http://github.com/jcinnamond/objectmother/wikis/home ? Congrats!
  20. Lucas Húngaro disse 1 dia depois:

    Note que testar um named_scope com proxy_options é testar o estado da classe, isto é, se existe no código a linha que cria o named_scope. Isto é um teste que deve ser feito no framework, para garantir a funcionalidade. Em seu software o que importa é comportamento da classe que, nesse casso, é retornar um vetor com alguns elementos já conhecidos (por isso temos a base de dados para testes sob nosso controle) e o que você deve testar é se esse resultado está correto. Isso evita que seu teste se torne quebradiço. Imagine que você descubra um bug no named_scope e precise retirá-lo da classe, substituindo por um find com condições iguais. Seu teste passará a quebrar sem que o comportamento da classe tenha sido alterado. Isso é um mau sinal.
  21. Lucas Húngaro disse 1 dia depois:

    Caramba, eu nem bebi e tô meio louco pra digitar. Casso = Caso Vão me mandar voltar pra escola! :D
  22. Lucas Húngaro disse 1 dia depois:

    Tapajós disse: "Não gosto do Shoulda pois ele tenta imitar um BDD sem ser." Cuidado, cuidado. Usar RSpec (ou Expectations, ou whatever...) não quer dizer que você faz BDD automaticamente. Isso não existe. Nos exemplos do post mesmo, o teste do named_scope utilizando proxy_options é um excelente exemplo de como testar estado com uma DSL feita para testar comportamento.
  23. Tapajós disse 1 dia depois:

    Lucas, com certeza você pode escrever testes de comportamento com o Shoulda assim como o inverso com o RSpec. Acredito que a estrutura do framework de teste te induz a fazer de uma forma no RSpec e de outra no Shoulda. Será que consegui me fazer claro?
  24. Lucas Húngaro disse 1 dia depois:

    Não. :) (Não me leve a mal, por favor. Sempre achei que temos que discutir mais sobre testes na comunidade... todo mundo fala que faz, mas ninguém comenta, discuti, passa o conhecimento etc). O que você faz com RSpec que não faz com Shoulda, expectations e outros? Testar o comportamento não depende do framework. Já vi muito teste bem feito, que assegura o comportamento, feito com Test::Unit e muito, mas muito mesmo, teste porco com RSpec.
  25. Lucas Húngaro disse 1 dia depois:

    É hoje hein... eu devia ter dormido direito. Discuti = Discute Aliás, meu primeiro comentário, onde cometi o abominável erro de escrever "casso" não apareceu. Ele foi moderado?
  26. Carlos Brando disse 1 dia depois:

    Você não usa Shoulda, ok, ok... mas você usa algum matcher para evitar ficar repetindo códigos nos testes com o RSpec? Todos os testes que você fez acima seriam umas 5 linhas com Shoulda, por exemplo. Eu sei que existem projetos como o rspec-on-rails-matchers para o RSpec que fazem o mesmo. Mas a pergunta é: Você usa? Recomenda? Qual a sua opinião sobre isto?
  27. Tim Case disse 1 dia depois:

    Já trabalhei com test unit e rspec muito, e eu prefiero shoulda. olha: should_require_attributes :name should_have_many :accounts
  28. Ronaldo Ferraz disse 1 dia depois:

    Elomar, sobre a questão de fixtures em testes unitários, existem benefícios e problemas. Fixtures podem tornar os seus testes unitários mais quebradiços, mas podem também torná-los mais reais. Não usar fixtures pode rapidamente levar à necessidade de testes como o de has_many acima que, embora válido em um certo sentido, está testando a declaração e não o comportamento. Brando, sobre as macros do Shoulda, eu tendo a evitá-las em muitos aspectos justamente porque também tendem a testar declarações e não comportamento. Especialmente as que envolvem o Rails vivem sendo vítimas de discussões por essa característica. O should_be_restful é um exemplo desse, que foi removido justamente pela opacidade. Muitos das macros envolvem esse tipo de problema e não refletem o mesmo comportamento dos matchers do RSpec. Dito isso, ultimamente meus testes tem sido Shoulda + RR. Tapajós, sobre indução de forma, tendo a discordar já que se o teste parte de arquitetura, comportamente saí naturalmente. Dito, isso, obrigado por instigar a discussão. O texto e os comentários estão se relevando bem instrutivos para a comunidade.
  29. Tapajós disse 1 dia depois:

    Akita, eu tenho usado o "Factory Girl" e estou gostando. O outro eu nunca usei. Pretendo escrever só sobre o "Factory Girl". Aguarde e confie! :-)
  30. Tapajós disse 1 dia depois:

    Lucas, seu comentário não foi moderado. Pode ser que o nosso sistema de blog tenha marcado como spam e alguém foi lá e marcou como confiavel, pois está aparecendo aqui. Não vou te levar a mal, é discutindo que se aprende. Não existe forma melhor de aprender do que tentar ensinar algo para alguém. Tinha certeza que iniciando essa série eu ia começar a aprender várias coisas. Tudo que eu faço com RSpec eu posso fazer com o Shoulda e realmente tem muito teste tosco com RSpec. Na verdade o que me faz gostar mais do RSpec é que ele é focado em comportamento, sua sintaxe foi criada para isso e cria meio que uma implicação implícita. Na minha opinião são visões diferentes. Mas veja bem, eu prefiro o RSpec mas isso não quer dizer que um seja melhor ou pior do que o outro. Indo mais além, não quer dizer que "BDD" é RSpec e Shoulda "TDD". Acho que nisso nos concordamos. Certo? Claro que nisso tudo entra a questão de gosto e de opiniões pessoais. Com relação ao meu teste de named\_scope eu concordo com você que ele não testa comportamento só que eu prefiri fazer dessa forma para não usar fixtures e além disso eu queria mostrar o proxy. Eu não gosto de usar fixtures para esse tipo de teste mesmo que eu precise sacrificar um pouco o teste de comportamento.
  31. Tapajós disse 1 dia depois:

    Carlos, eu só conheço um desses projetos que é o [Skinny Spec][ss]. Tenho usado ele em uns projetos lá na Surgeworks e no geral estou satisfeito. Algumas coisas eu mesmo implemento no meu spec\_helper e depois reuso. Por questões de didática preferi não cita-los pois queria mostrar como testar mesmo. Mostrar como as coisas funcionam ao invés de mostrar apenas chamadas que ninguém sabe como funcionam. Para nós que já temos experiência no assunto meus testes podem parecer bem tolos, mas a idéia desse post é ajudar quem conhece muito pouco de testes. Acho que eu não precisaria escrever um artigo de testes voltado aos experts em testes pois com certeza sou eu que tenho que aprender com eles. [ss]: http://github.com/rsl/skinny_spec
  32. Tapajós disse 1 dia depois:

    Tim, dá para fazer isso que você citou em RSpec usando o Skinny Spec.
  33. Tapajós disse 1 dia depois:

    Ronaldo, esse é o espirito, fomentar discussões e levar ao aprendizado. Obrigado pelo seu feedback.
  34. Vinícius Manhães Teles disse 1 dia depois:

    Bom trabalho, Tapa!!! :) Não pára! Não pára! Não pára! Não pára! Grande abraço, Vinícius.
  35. Carlos Brando disse 1 dia depois:

    Eu confesso que o único motivo de usar Shoulda ao invés de RSpec são as macros do Sholda. Mas eu sou um zé mané quando se fala de testes. Por favor, continue com esta série... tem muita coisa ainda que precisa ser dita.
  36. Lucas Húngaro disse 2 dias depois:

    Tapajós, dá pra você substituir todas as fixtures por factories (uso factory_girl pra isso) e manter os testes limpos. Manda bala nos posts porque, como eu disse anteriormente, pouco se fala sobre isso na comunidade.
  37. Pedro Valentini disse 2 dias depois:

    Legal o artigo, obrigado! Exemplos práticos são a melhor forma de aprender, ja li bastante sobre testes de software mas ainda não fazem parte do meu dia-a-dia. Isso vai ser um incentivo, vou usar no Sociare =] Abs, Pedro
  38. Andressa disse 3 dias depois:

    Ótimo post! Concordo quando dizem que é muito bom abordar este assunto, já percebi que muitas pessoas ainda não entraram de verdade no mundo dos testes. Sobre a questão de uma assertion por teste, discuti exatamente isso com minha orientadora de um projeto de pesquisa e o que ela me disse me convenceu: Imagine que você possui uma aplicação grande, com vários testes, sendo que para rodar todos você gasta um tempo considerável. Se há mais de uma assertion em cada teste (método) e se a primeira já falha, você não possui garantia nenhuma de que as outras assertions desse mesmo teste (método) estão corretas. Assim, se na primeira vez você corrigiu 5 falhas, na próxima vez você teria que esperar todos os testes rodarem novamente e ainda correr o risco de surgir novas falhas que já poderiam ter sido identificadas anteriormente. Se há somente uma assertion por teste, você consegue identificar logo na primeira "rodada" todas as falhas daqueles testes e pode corrigí-las de uma vez. Bem, me convenceu. Não se se convence a vocês, rs. E desculpe se isso for óbvio demais, rs. Estou iniciando nesse universo dos testes ainda! Parabéns e abraços! ^^
  39. Lucas de Castro disse 4 dias depois:

    Parabéns Tapajós, ótimo post!
  40. Ricardo Almeida disse 4 dias depois:

    Muito Bom Tapajós! Parabéns. Você está motivando bastante gente a estudar mais sobre testes. Eu também tinha escutado sua entrevista no RailsBox e achei que foi uma verdadeira aula. Escrevi alguns posts no meu blog relativos a testes, mas não foi nada tão prático como esse excelentente post. Valeu!
  41. Ramon Soares disse 11 dias depois:

    Muito bom artigo. Mas tem um erro: `VALIDS_MAIL = %w(foo@bar.com foo@bar.com.br foo@globo.com foo@i_hate_the_microsoft.com foo@i_love_my_mac.com)` n são permitidos domínios com _ (i_hate_the_microsoft.com e/ou i_love_my_mac.com). axo que uma melhor regex pra valida email seria: `/\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i`
  42. Thiago disse 11 dias depois:

    Parabéns pelo artigo e continue com a série, está sendo de grande valia. Me tira uma dúvida, é realmente interessante fazer testes que checam se a mensagem de erro é igual a uma string? E se sobreescreverem a mensagem de erro da validação, ou se utilizarem internacionalização?
  43. elomarns disse 23 dias depois:

    Sei que esse post já é meio antigo (22 dias na Web é uma eternidade), mas só pude ler agora, e não posso deixar de dizer que ele foi excelente. O artigo mostrou exemplos bem claros, mesmo para quem não sabe muito sobre testes, como eu, que sei bem pouco sobre RSpec e posso dizer que já aprendi a escrever alguns testes básicos com ele. A maior prova disso é que eu escrevi o teste do named scope com RSpec logo após ver o mesmo teste com Test::Unit, e vi que escrevi exatamente como indicado no artigo. Além disso, aprendi alguns recursos do Rails interessantes, como o reflect_on_association e o proxy\_options, sendo que esse último eu já tinha visto, mas não tinha parado pra ver como funciona. Em relação a filosofias ao elaborar os testes, eu sou mais voltado a testar o comportamento, por isso estranhei um pouco o teste do named scope, mas acho que isso varia conforme as preferências pessoais e com a aplicação em questão, não existindo algo que possa ser considerado como o jeito definitivamente certo. Sobre a questão de uma asserção por teste, apesar de estranhar inicialmente, me parece uma boa idéia, principalmente depois dos argumentos apresentados. Por fim, não tem como deixar de mencionar os comentários de altíssimo nível desse post. Graças a eles e aos links postados eu aprendi um monte de outras coisas bem interessantes. Enfim, parabéns pela excelente idéia de publicar essa série de posts.
  44. Rodrigo Reginato disse aproximadamente 1 mês depois:

    legal o reflect_on_association, curti muito!! valew
  45. Rafael Quintana disse 2 meses depois:

    Fala pessoal, O ActiveRecord é muito bom mesmo, inclusive tem inspirando outros projetos em outras plataformas, como o iPhone. Isso mesmo, existe ActiveRecord para iPhone e é muito parecido com o de Ruby on Rails, só que é em Objective C. Escrevi um pouco sobre ele nesse link: http://www.mobits.com.br/2009/1/6/mapeamento-objeto-relacional-no-iphone Abraços e sucesso a Improve It!
  46. Guilherme disse 2 meses depois:

    Parabéns, excelente artigo ! :D show de bola! Podia ter mais.. haha =D