Recentemente me deparei com um dos piores cenários quando estamos testando: o falso positivo. Aconteceu usando os testes para uma visão (view) com o RSpec e o Webrat. Vamos dar um exemplo para depois explicar o motivo:
Digamos que eu estou a exibição da tela de um usuário quando estou logado como administrador. Quero testar se ao visitar a página, vejo o link de administração. Veja um exemplo da página:
<h1>Usuário José</h1>
<div id="submenu"> <a href="/admin/users/1">administrar usuário</a>
</div>
<p id="profile">
Site pessoal:
<a href="http://www.mysite.com">my site</a>
</p>
O teste que eu fiz, usando um usuário administrador, dizia:
describe "an admin user" do
it "should have an admin link" do
 @user.admin?.should be_true
visit user_path(1)
 response.should have_tag("a", :href => admin_user_path(1))
end
end
E o teste foi bem sucedido. O problema é que, logo depois, eu resolvi que era importante garantir que um usuário não administrador não veria o link (afinal, não fazia sentido para o perfil dele). Então fiz o teste:
describe "a regular user" do
it "should not have an admin link" do
 @user.admin?.should be_false
visit user_path(1)
 response.should_not have_tag("a", :href => admin_user_path(1))
end
end
E o teste falhou, indicando que havia o link. Corri para conferir na página, mas o código estava correto. Então, procurando na internet (ver links úteis abaixo), entendi melhor o ocorrido. O método have_tag não possui a opção de testar :href como eu tinha definido. E, portanto, a única coisa que eu estava testando é se havia algum link na página. A resposta era sim, portanto, falhava o teste.
O método have_tag apenas navega no DOM. Por isso, para que ele teste corretamente, podemos fazer de 2 jeitos:
1) Usando o have_tag, farÃamos:
response.should have_tag("a[href=?]", admin_users_path(1))
ou
response.should have_tag("a[href*=?]", /admin\/users/)
2) PoderÃamos usar também o have_selector. As opções ficam mais amplas:
response.should have_selector("a", :href => admin_users_path(1))
Usando o have_tag com o with_tag
O teste ficaria ainda mais interessante se limitássemos o escopo de busca pelo link. PoderÃamos fazer dessa forma:
response.should have_tag("div#submenu") do with_tag("a[href=?]", admin_users_path(1)) end
E, para o caso do usuário não ser administrador:
response.should have_tag("div#submenu") do without_tag("a[href=?]", admin_users_path(1)) end
Usando o have_tag com o have_selector
Podemos também usar o have_selector com o have_tag:
response.should have_tag("div#submenu") do have_selector("a", :href => admin_users_path(1)) end
E, da mesma forma, para o caso do usuário não ser administrador:
response.should have_tag("div#submenu") do have_no_selector("a", :href => admin_users_path(1)) end
Uma coisa importante é que o uso do have_no_selector pode se dar apenas dentro de um bloco have_tag. Até porque, sem estar dentro do bloco, faria mais sentido usar:
response.should_not have_selector("a", :href => admin_users_path(1))
Links Úteis: