ruby - tutorial - using rubocop




Tamanho do bloco da linha Rubocop 25 e testes RSpec (2)

Um teste unitário típico do RSpec faz uso extensivo de blocos Ruby aninhados para estruturar o código e fazer uso da "mágica" do DSL para que as especificações sejam lidas como instruções do BDD:

describe Foo do
  context "with a bar" do
    before :each do
      subject { Foo.new().add_bar }
    end

    it "looks like a baz" do
      expect # etc

Em uma especificação ideal, cada exemplo pode ser relativamente curto e preciso. No entanto, parece normal que os blocos externos cresçam para 100 linhas mais, porque a estrutura RSpec funciona dessa maneira e não leva muitos exemplos de especificação, cada um dos quais pode ter algumas linhas de configuração específica, para describe blocos que são o mesmo tamanho ou maior que o código para o assunto que está sendo descrito.

Uma recente atualização do Rubocop trouxe uma nova regra em jogo, que os blocos não devem ter mais de 25 linhas. Não tenho certeza do motivo para isso, porque não está listado no guia de estilo Ruby . Eu posso ver porque isso poderia ser uma coisa boa e adicionado ao conjunto de regras padrão. No entanto, após a atualização, o nosso teste Rubocop falha várias vezes com mensagens como tests/component_spec.rb:151:3: C: Block has too many lines. [68/25] tests/component_spec.rb:151:3: C: Block has too many lines. [68/25]

Com ferramentas de métrica de código, como Rubocop, eu gosto de ter uma política de "Usar os padrões, link para o guia de estilo, trabalho feito." (principalmente porque debater tabulações versus espaços e outras minúcias está perdendo tempo, e o IME nunca é resolvido) Aqui claramente não é possível, duas de nossas principais ferramentas de qualidade de dados discordam sobre a abordagem de layout de código - ou pelo menos é assim que eu interpreto os resultados , Não vejo nada de intrinsecamente errado em como escrevemos as especificações.

Em resposta, simplesmente definimos a regra de tamanho de bloco Rubocop para um limite alto. Mas isso me faz pensar - o que estou perdendo? O RSpec está usando uma abordagem agora desacreditada para o layout de código e quais opções razoáveis eu tenho para reduzir os tamanhos de bloco em nossos testes de RSpec? Eu posso ver maneiras de reestruturar o código para evitar grandes blocos, mas eles são, sem exceção, hacks feios destinados apenas a atender a regra de Rubocop, por exemplo, quebrar todos os blocos em funções auxiliares:

def looks_like_a_baz
  it "looks like a baz" do
         expect # etc
  end
end

def bar_context
  context "with a bar" do
    before :each do
      subject { Foo.new().add_bar }
    end
    looks_like_a_baz
  end
end


describe Foo do
  bar_context
  # etc

. . . Quero dizer, isso é possível, mas transformar grupos de exemplos de especificação em funções auxiliares dessa maneira parece ser o oposto da abordagem legível encorajada pelo design do RSpec.

Há mais alguma coisa que eu possa fazer além de encontrar maneiras de ignorá-lo?

A pergunta mais próxima que encontrei sobre esse tópico aqui foi o RSpec & Rubocop / Ruby Style Guide e isso pareceu ser solucionável com a edição de modelos de teste.


Uma recente atualização do Rubocop trouxe uma nova regra em jogo, que os blocos não devem ter mais de 25 linhas. Não tenho certeza do motivo para isso, porque não está listado no guia de estilo Ruby.

Costumava ser que todos os policiais eram baseados no The Ruby Style Guide, e o RuboCop era uma maneira de aderir às práticas estabelecidas pela comunidade.

A direção mudou desde então, e o escopo do RuboCop foi expandido para ajudar os desenvolvedores a garantir consistência em suas bases de código em geral. Isso levou a duas coisas:

  1. Os policiais (mesmo aqueles baseados no The Ruby Style Guide) agora são configuráveis.
  2. Há policiais para coisas que não são mencionadas no Ruby Style Guide, mas ainda são úteis para reforçar a consistência em um projeto.

Este policial cai na segunda categoria.

O RSpec está usando uma abordagem agora desacreditada para o layout de código e quais opções razoáveis ​​eu tenho para reduzir os tamanhos de bloco em nossos testes de RSpec?

Resposta curta é não. As DSLs ainda são legais. :-)

Este policial é destinado a grande bloco no sentido de programação imperativa. Como um guia geral, não se aplica às DSLs, que são frequentemente declarativas. Por exemplo, ter um arquivo routes.rb longo no Rails é perfeitamente benigno. É apenas um resultado natural de um aplicativo grande, em vez de uma violação de estilo. (E ter muitos testes é simplesmente incrível.)

Agora, o RuboCop é bastante inteligente, mas não sabe o que é uma DSL e não, por isso não podemos ignorá-los automaticamente. Pode-se argumentar que poderíamos excluir métodos de entrada DSL de estruturas populares, como rotas Rails e especificações RSpec. As razões para não fazer isso são principalmente:

  1. Falsos negativos. Qualquer classe pode implementar um método, tomando um bloco, com o mesmo nome.
  2. O RuboCop é uma ferramenta de análise Ruby e não deve conhecer as bibliotecas externas. (Excluir o diretório /spec é uma cortesia até que tenhamos um sistema de extensão adequado, e isso pode ser tratado pela gem rubocop-rspec .)

Quero dizer, isso é possível, mas transformar grupos de exemplos de especificação em funções auxiliares dessa maneira parece ser o oposto da abordagem legível encorajada pelo design do RSpec.

A questão é: o RuboCop está lá para nos ajudar a escrever um código melhor. Se o design de nosso aplicativo for de outra forma sólido, e nos encontrarmos tornando as coisas menos legíveis meramente para agradar o RuboCop, então devemos filtrar, configurar ou desabilitar o policial. :-)

Em resposta, simplesmente definimos a regra de tamanho de bloco Rubocop para um limite alto. Mas isso me faz pensar - o que estou perdendo?

Esta é uma ferramenta bastante contundente e, como você está insinuando, você provavelmente terá alguns falsos negativos por causa disso. Existem dois tipos de falsos positivos para este policial:

  1. Arquivos que contêm DSLs puramente declarativas, por exemplo, rotas Rails, especificações RSpec.
  2. Arquivos que possuem uma DSL declarativa misturada principalmente em código imperativo, por exemplo, uma declaração de máquina de estado aasm em um modelo Rails.

No primeiro caso, a melhor solução é excluir o arquivo ou diretório e, no segundo, usar uma desativação inline.

No seu caso, você deve atualizar seu .rubocop.yml com:

Metrics/BlockLength:
  Exclude:
    - 'Rakefile'
    - '**/*.rake'
    - 'test/**/*.rb'

(Observe que você precisa reiterar as exclusões básicas da configuração padrão, pois a lista será sobrescrita.)


Se um bloco específico é geralmente muito longo, eu especifico em vez de os arquivos

Metrics/BlockLength:
  ExcludedMethods: ['describe', 'context']




rubocop