ruby - guides - rspec tutorials




Módulos de teste no rspec (8)

Quais são as melhores práticas em testar módulos no rspec? Eu tenho alguns módulos que são incluídos em poucos modelos e por enquanto eu simplesmente tenho testes duplicados para cada modelo (com poucas diferenças). Existe uma maneira de secar?


A resposta aceita é a resposta certa, no entanto, gostaria de acrescentar um exemplo de como usar os métodos rpsecs shared_examples_for e it_behaves_like . Eu menciono alguns truques no snippet de código, mas para mais informações, veja este relishapp-rspec-guide .

Com isso, você pode testar seu módulo em qualquer uma das classes que o incluem. Então você está realmente testando o que você usa na sua aplicação.

Vamos ver um exemplo:

# Lets assume a Movable module
module Movable
  def self.movable_class?
    true
  end

  def has_feets?
    true
  end
end

# Include Movable into Person and Animal
class Person < ActiveRecord::Base
  include Movable
end

class Animal < ActiveRecord::Base
  include Movable
end

Agora vamos criar especificações para o nosso módulo: movable_spec.rb

shared_examples_for Movable do
  context 'with an instance' do
    before(:each) do
      # described_class points on the class, if you need an instance of it: 
      @obj = described_class.new

      # or you can use a parameter see below Animal test
      @obj = obj if obj.present?
    end

    it 'should have feets' do
      @obj.has_feets?.should be_true
    end
  end

  context 'class methods' do
    it 'should be a movable class' do
      described_class.movable_class?.should be_true
    end
  end
end

# Now list every model in your app to test them properly

describe Person do
  it_behaves_like Movable
end

describe Animal do
  it_behaves_like Movable do
    let(:obj) { Animal.new({ :name => 'capybara' }) }
  end
end

Eu encontrei uma solução melhor na homepage rspec. Aparentemente, ele suporta grupos de exemplos compartilhados. Em https://www.relishapp.com/rspec/rspec-core/v/2-13/docs/example-groups/shared-examples !

Grupos de Exemplo Compartilhados

Você pode criar grupos de exemplos compartilhados e incluir esses grupos em outros grupos.

Suponha que você tenha algum comportamento que se aplique a todas as edições de seu produto, grandes e pequenas.

Primeiro, considere o comportamento “compartilhado”:

shared_examples_for "all editions" do   
  it "should behave like all editions" do   
  end 
end

em seguida, quando você precisar definir o comportamento para as edições Large e Large, faça referência ao comportamento compartilhado usando o método it_should_behave_like ().

describe "SmallEdition" do  
  it_should_behave_like "all editions"
  it "should also behave like a small edition" do   
  end 
end

Fora do topo da minha cabeça, você poderia criar uma classe fictícia no seu script de teste e incluir o módulo nisso? Em seguida, teste que a turma dummy tem o comportamento da maneira esperada.

EDIT: Se, como apontado nos comentários, o módulo espera que alguns comportamentos estejam presentes na classe em que está misturado, então eu tentaria implementar dummies desses comportamentos. Apenas o suficiente para tornar o módulo feliz em realizar suas tarefas.

Dito isto, eu ficaria um pouco nervoso com o meu design quando um módulo espera muito da sua classe host (digamos "host"?) - Se eu já não herdar de uma classe base ou não puder injetar a nova funcionalidade na árvore de herança, então eu acho que estaria tentando minimizar quaisquer expectativas que um módulo possa ter. Minha preocupação era que meu projeto começaria a desenvolver algumas áreas de inflexibilidade desagradável.


O caminho rad =>

let(:dummy_class) { Class.new { include ModuleToBeTested } }

Alternativamente, você pode estender a classe de teste com o seu módulo:

let(:dummy_class) { Class.new { extend ModuleToBeTested } }

Usar 'let' é melhor do que usar uma variável de instância para definir a classe dummy no before (: each)

Quando usar o RSpec let ()?


Para módulos que podem ser testados isoladamente ou zombando da classe, gosto de algo nos moldes de:

módulo:

module MyModule
  def hallo
    "hallo"
  end
end

spec:

describe MyModule do
  include MyModule

  it { hallo.should == "hallo" }
end

Pode parecer errado seqüestrar grupos de exemplo aninhados, mas eu gosto da clareza. Alguma ideia?


Sobre o quê:

describe MyModule do
  subject { Object.new.extend(MyModule) }
  it "does stuff" do
    expect(subject.does_stuff?).to be_true
  end
end


meu trabalho recente, usando o mínimo de hard-fiação possível

require 'spec_helper'

describe Module::UnderTest do
  subject {Object.new.extend(described_class)}

  context '.module_method' do
    it {is_expected.to respond_to(:module_method)}
    # etc etc
  end
end

Eu gostaria

subject {Class.new{include described_class}.new}

funcionou, mas não funciona (como em Ruby MRI 2.2.3 e RSpec :: Core 3.3.0)

Failure/Error: subject {Class.new{include described_class}.new}
  NameError:
    undefined local variable or method `described_class' for #<Class:0x000000063a6708>

Obviamente, describe_class não é visível nesse escopo.





rspec