Ao tentar executar a suite de testes em uma Rails Engine fui surpreendido com alguns erros, então partir para campo afim de descobrir o porquê das coisas não funcionarem convencionalmente como se esperava. Na página Issues do Rails no GitHub vi que se tratava de bugs do Rails mesmo, no meu caso a versão 3.2.8.
Como não era somente um bug para corrigir e não achei um post relacionando todos, depois da garimpada na net, resolvi juntar tudo e postar aqui.
Vou fazer um exemplo de execução de testes em uma Engine para exemplificar melhor. Nossa mega Engine vai se chamar Blog (nesse momento estou inspirado), vamos lá então.
Não vou entrar em detalhes sobre Rails Engine, se você não tem noção nenhuma do que seria isso pode começar aqui: http://www.akitaonrails.com/2010/05/10/rails-3-introducao-a-engines#.UIqn32lUMzE - (Sto. @AkitaOnRails).
Futuramente (quando a faculdade deixar) pretendo fazer um exemplo para documentar também, ai coloco o link aqui ;)
Criando uma Rails Engine
Vamos criar nossa app Blog.
1 2 |
|
Vimos que criamos uma Engine isolada, dessa forma nossas classes serão englobadas no namespace Blog e criadas dentro de pastas nomeadas pelo namespace.
Agora vamos gerar um Scaffold para ter o que testar ;P
1
|
|
Em uma Engine, temos tarefas rake específicas prefixadas com “app”, as que nos interessam nesse momento são as relativas ao banco de dados
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Vamos criar nosso DB e executar as migrações
1 2 3 4 5 6 7 |
|
Observe que a tabela criada é prefixada pelo nome da Engine.
Com o scaffold criamos toda a estrutura para os testes.
Enfim, vamos aos erros.
ERROS
O scaffold já cria os testes funcionais para CRUD, veja o arquivo test/functional/blog/posts_controller_test.rb
,
dessa forma já podemos executar os testes e ver se está tudo funfando.
1
|
|
Ops! deu pau ;(
1) NoMethodError: undefined method `posts’ for #<Blog::PostsControllerTest:0x007f942c045ed0>
Esse error acontece devido nosso controller tentar carregar as fixtures do post que não foram carregadas/criadas, veja:
1 2 3 4 5 6 7 |
|
Você precisa explicitar isso para o ActiveSupport::TestCase,
abra o arquivo test/test_helper.rb
e adicione: ActiveSupport::TestCase.fixtures :all
no contexto onde as fixtures são carregadas.
1 2 3 4 5 |
|
Agora rode os testes;
1
|
|
Ops! deu pau ;(
2) ActiveRecord::StatementInvalid: Could not find table ‘blog_posts’
Esse error é devido as convenções não funcionarem aqui, se você reparou o path das fixtures está setado para raiz da pasta fixtures, então vamos alterar.
1 2 3 4 5 |
|
Agora rode os testes;
1
|
|
Ops! deu pau ;(
3) ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: posts: DELETE FROM “posts”
Como convenção, a fixture post tenta utilizar a tabela post, mais como vimos, estamos “namespaceados” pelo nome da engine,
então precisamos novamente explicitar para o ActiveSupport::TestCase que o objeto utilizado pela fixture post é Blog::Post
,
dessa forma o ActiveRecord referencia a tabela correta.
Então adicione mais uma linha no seu test_helper.rb
1 2 3 4 5 6 |
|
Agora rode os testes;
1
|
|
Ops! deu pau ;(
4) ActionController::RoutingError: No route matches {:id=>”980190962”, :post=>{:body=>”MyText”, :title=>”MyString”}, :controller=>”blog/posts”, :action=>”update”}
Vamos observar o arquivo de rotas, config/routes.rb
1 2 3 |
|
Realmente não temos a rota ‘blog/posts’ criada e não devemos criar, pois quando montamos nossa Engine em uma App mãe, essa rota será criada devido nossa Engine ser isolada (–mountable), então a App precisa diferenciar a requisição ao controller post da Engine da requisição do controller post dela mesma (caso tenha).
Não sei se expliquei bem, mais é só para justificar o porquê de não alterar esse arquivo.
Para resolver isso, vamos disponibilizar diretamente ao controller_test as rotas.
Em test/functional/blog/posts_controller_test.rb
adicione:
1 2 3 4 |
|
Agora rode os testes;
1
|
|
Congratulation!
Agora nossa suite de teste esta rodando, já podemos trabalhar. :P
Tentei explicar as correções de forma que quem esteja começando no mundo Rails possa entender o que está acontecendo e não simplesmente copiar e colar o código para correção. Lembrando que também sou um aspirante Rails e estou aberto para correções neste post caso cometi alguma gafe.