Testing relationships in Rails

Posted March 18, 2008 by Filipe
Categories: rails, testing

Tags: ,

Ler este artigo em português

I’ve been looking for an elegant way to test relationships using Rais, and think it’s interesting how so few people really care about it. Most simply say that it’s up to the framework to test it’s own functions. Yeah, right, has_many and belongs_to have been tested before, but you should be aware that it’s up to you to check out the code you right. So, you have to make sure that a simple has_many :comments is really where it should be, so you should test it. Anyway, I listed some approaches I’ve found:

1 – Using fixtures:

At first, I thought about using fixtures, writing the relationships inside it (Rails 2.0). It’s a simple solution, but it has a downside. When we declare dependencies on the fixtures, and the relationship isn’t on the model, it’ll raise an error instead of a test failing. e.g.:

# post.rb

class Post < ActiveRecord::Base

end# comment.rb

class Comment < ActiveRecord::Base

end

# posts.yml

testing_relationships:

  title: Hello World

  body: Hello...

# comments.yml

commenting_relationships:

  body: I disagree!

  author: Filipe Coimbra

  post:  testing_relationships

As I haven’t said that Comment belongs_to :post, when a test that calls comments.yml is called, an error will be raised. Besides, the other dependency, Post has_many :comments won’t be tested.
Besides, it’s not a cool thing to use fixtures as if they were tests. Besides, they’re not automatically documented.

2 – Again using fixtures:

After a while, I found this arcticle, which also uses fixtures, but with a different approach (a little bit Rails 1.2-ish) just defining the relation through the foreign key. That way, no error will happen.
It works, although you just have to test your own code, the rest is up to ActiveRecord. But, you may won’t like using fixtures because they may broke when you change your table structure.

3 – The wrong option that works:

Finally, I ended up using the most logical solution, that is writing ruby code, based on this post by Err The Blog.

# post_spec.rb

describe Post do

  before(:each) do

    @post = Post.new

  end   it "should be related to comments" do

    comment = Comment.new(:body => "Testing relationships")

    @post.comments << comment

    @post.comments.should include(comment)

  end

end

# comment_spec.rb

describe Comment do

  before(:each) do

    @comment = Comment.new

  end

  it "should be related to a post" do

    post = Post.new

    @comment.post = post

    @comment.should equal(post)

    @comment.post.should equal(post)

  end

end

It’s simple and easy, but… why is it wrong? When I write “@post.comments << comment”, I’m calling a method comments on the object @post. As I didn’t declare that Post has_many :comments, this will be a missing method. Fortunately it works because rSpec won’t raise any errors, and just will tell us that the spec fails.
Even so, I still prefer this approach as I won’t be dealing with fixtures.

Testando relacionamentos no Rails

Posted March 18, 2008 by Filipe
Categories: rails, testing

Tags: ,

Read this acticle in English

Estive procurando por uma maneira elegante de testar relacionamentos utilizando Rails, e achei interessante como pouca gente está preocupada com isso. Na maioria das vezes, dizem simplesmente que isto é função do próprio framework. Tudo bem, o has_many e belongs_to (esqueça que existe o HBTM) já foram devidamente testados, mas é importante saber que o que cabe a você testar o que você escreve no seu código. Portanto, se você quer ter certeza que a linha has_many :comments realmente existe, você deve escrever um teste para ela. Então, resolvi listar algumas abordagens:

1 – Utilizando fixtures:

No começo, pensei em utilizar as fixtures, mas usando relacionamentos dentro delas. É uma solução simples, porém traz um revés. Quando utilizamos um relacionamento dentro das fixtures, e este relacionamento não está explicitado nos models, será retornado um erro, ao invés de uma falha. Por exemplo:

# post.rb

class Post < ActiveRecord::Base

end# comment.rb

class Comment < ActiveRecord::Base

end

# posts.yml

testing_relationships:

  title: Hello World

  body: Hello...

# comments.yml

commenting_relationships:

  body: I disagree!

  author: Filipe Coimbra

  post:  testing_relationships

Como não foi explicitamente dito que Comment belongs_to :post, ao se executar a fixture comments.yml será retornado um erro. Além disso, o relacionamento contrário, Post has_many :comments não será testado.

2 – Novamente utilizando fixtures:

Depois, encontrei este artigo, que também utiliza fixtures com uma abordagem diferente (e mais Rails 1.x) que é definir apenas a chave estrangeira na fixture. Assim, não seria retornado erro.
É funcional, mas eu quero apenas testar se as linhas de relacionamento estão definidas nos models. O resto, fica por conta do ActiveRecord. Além disso, não quero usar fixtures como se fossem testes, já que, primeiro, não são documentadas automaticamente (como no caso dos métodos de teste) e porque, caso você mude a estrutura da sua tabela, poderá ter seus testes quebrados por causa das fixtures que não refletem as mudanças.

3 – A opção errada que funciona:

Acabei utilizando a solução mais lógica, e baseada neste post do Err The Blog.

# post_spec.rb

describe Post do

  before(:each) do

    @post = Post.new

  end  it "should be related to comments" do

comment = Comment.new(:body => "Testing relationships")

    @post.comments << comment

    @post.comments.should include(comment)

  end

end

# comment_spec.rb

describe Comment do

  before(:each) do

    @comment = Comment.new

  end

it "should be related to a post"

    post = Post.new

    @comment.post = post

    @comment.should equal(post)

    @comment.post.should equal(post)

  end

end

É simples, mas… por que é errada? Quando fazemos “@post.comments << comment”, estamos chamando o método comments do objeto @post. Como não foi declarado que Post has_many :comments, este método não existirá. Ela funciona porque o rSpec não acusará o erro, e apenas retornará uma falha no teste.
Ainda assim, prefiro essa solução porque eu não precisarei lidar com fixtures.

Notas sobre o NetBeans 6

Posted December 6, 2007 by Filipe
Categories: rails

Tags:

Foi lançada a versão final do NetBeans 6, com a promessa de ser a melhor IDE de desenvolvimento para Ruby/Ruby on Rails. E, realmente, para uma IDE, ele parece estar no caminho certo. Apesar de um ou outro bug que aparecem de quando em quando (versão para linux, rodando no Ubuntu 7.10), o funcionamento está razoável. Quando se cria um projeto em RoR, a separação das áreas (Controllers, Models, Views, Helpers) está mais lógica que a separação de pastas padrão do Rails. O Code Completion, que tantos adoram, é bastante interessante, inclusive completando os atributos de um Model através dos campos existentes no banco de dados. Toda a ajuda referente a métodose classes do Code Completion parece ter sido retirada das APIs oficiais do Ruby on Rails e do Ruby.

O NetBeans também possui acesso direto aos comandos do /script/ e do rake através da sua interface, integração com CSV e Subversion, debugger (caso o Fast Debugger esteja instalado – o que pode ser feito através da própria IDE), controle de Plugins do RoR, dentre outras features.

Enfim, não fui muito a fundo, por enquanto, mas, para mim, um bom editor de textos, o shell do Linux e o railsapi.org em conjunto podem ser tão produtivos quanto o NetBeans, além de bem mais leves. Para quem gosta de IDEs, pode realmente valer a pena. Talvez, caso a pessoa utilize Windows (que tem um shell bem chatinho para se usar com o RoR), a experiência seja bem melhor.

/** @todo Acionar o AdSense e começar a ganhar milhões com o blog **/

Posted September 20, 2007 by Filipe
Categories: cakephp, devaneios

Finalmente, foi superado o trauma do primeiro post, ainda agravado por uma mudança de ferramenta. Ainda estou tentando descobrir duas coisas: primeiro, um bom e agradável layout; segundo, saber exatamente o que colocar nesta caixinha de texto.

(…)

E eu continuo minha saga com o famigerado ORM do Cakephp. Na maioria das vezes, é só um inconveniente. Algumas, é realmente irritante.

Precisei fazer uma busca em uma tabela utilizando um valor que deveria ser buscado a 4 relacionamentos de distância. Até aí, nada demais, penso eu. No Rails, eu poderia utilizar uma cascata de :include e :through, dependendo do caso. Então eu creio que, no Cake, eu possa fazer simplesmente:

$this->ModelName->recursive = 4;
$this->ModelName->find('ModelDistante.field = ' . $value);

Certo? Claro que não. Após alguns minutos revirando o código, eu resolvo mudar o log para exibir as queries executadas. Para minha surpresa, apenas a primeira recursividade é utilizada na primeira query. Após isto, o Cake vai iterando pelo resultado e resgatando os dados relacionados aos demais níveis da recursividade. Bizarro.
A solução é criar a query (utilizando o método Model::query()) na mão, o que é um tanto ilógico já que se opta a utilizar um ORM para não precisar fazer o trabalho duro.
Ainda bem que foi a primeira vez em mais de um mês no projeto. No mais, o Cake tem se mostrado um framework razoavelmente bom. Tem várias limitações, claro. Espero que em versões futuras mudem o ORM.

Primeira postagem… sobre o quê?

Posted September 17, 2007 by Filipe
Categories: cakephp, devaneios, php, rails

Qual o foco deste blog? Sei lá, talvez uma espécie de “meu querido diário…”. Ou quem sabe só uma ferramenta para descarregar o estresse escrevendo besteiras e xingando a mãe dos outros. Que seja.

(…)

Tive, finalmente, a felicidade de terminar o primeiro projeto usando o CakePHP. Conclusões? Se puder, use Rails (ou o Symphony, caso queira mesmo continuar com o PHP).
Não que o CakePHP seja de todo ruim… Só tem um longo caminho a evoluir, principalmente o ORM. Não sei quem teve a idéia de criar a recursividade ao se resgatar dados de tabelas relacionadas, só sei que foi bem infeliz. Muito melhor criar um XML com os dados das tabelas, como no Symphony.
Além disto, eles tentaram copiar a idéia dos partials do Rails, mas todos os partials devem ser salvos num diretório “views/elements”, o que deixa tudo um pouco confuso.
Sempre li que o Symphony é muito inchado de features, muitas delas desnecessárias. Pode ser, mas ainda assim é melhor, já que funciona como deveria.