Domanda RSpec: come testare le aspettative dei messaggi del registratore di Rails?


Sto cercando di verificare che il registratore di Rails riceva i messaggi in alcune delle mie specifiche. Sto usando il Gemma di registrazione.

Diciamo che ho una classe come questa:

class BaseWorker

  def execute
    logger.info 'Starting the worker...'
  end

end

E una specifica come:

describe BaseWorker do

  it 'should log an info message' do
    base_worker = BaseWorker.new
    logger_mock = double('Logging::Rails').as_null_object
    Logging::Rails.stub_chain(:logger, :info).and_return(logger_mock)

    logger_mock.should_receive(:info).with('Starting the worker...')
    base_worker.execute
    Logging::Rails.unstub(:logger)
  end

end

Ottengo il seguente messaggio di errore:

 Failure/Error: logger_mock.should_receive(:info).with('Starting worker...')
   (Double "Logging::Rails").info("Starting worker...")
       expected: 1 time
       received: 0 times

Ho provato diversi approcci diversi per far passare le specifiche. Questo funziona ad esempio:

class BaseWorker

  attr_accessor :log

  def initialize
    @log = logger
  end

  def execute
    @log.info 'Starting the worker...'
  end

end

describe BaseWorker do
  it 'should log an info message' do
    base_worker = BaseWorker.new
    logger_mock = double('logger')
    base_worker.log = logger_mock

    logger_mock.should_receive(:info).with('Starting the worker...')
    base_worker.execute
  end
end

Ma dovendo impostare una variabile di istanza accessibile come quella sembra che la coda scodinzoli qui. (In realtà, non sono nemmeno sicuro del motivo per cui copiare il logger su @log lo farebbe passare).

Qual è una buona soluzione per testare la registrazione?


44
2018-06-12 13:54


origine


risposte:


Mentre sono d'accordo che generalmente non vuoi testare i logger, ci sono momenti in cui può essere utile.

Ho avuto successo con le aspettative Rails.logger.

Utilizzo di RSpec deprecato should sintassi:

Rails.logger.should_receive(:info).with("some message")

Usando RSpec più recente expect sintassi:

expect(Rails.logger).to receive(:info).with("some message")

Nota: Nel controller e nelle specifiche del modello, devi mettere questa linea prima il messaggio è registrato Se lo metti dopo, riceverai un messaggio di errore come questo:

Failure/Error: expect(Rails.logger).to receive(:info).with("some message")
       (#<ActiveSupport::Logger:0x007f27f72136c8>).info("some message")
           expected: 1 time with arguments: ("some message")
           received: 0 times

90
2017-07-11 05:41



Con la versione RSpec 3+

Codice reale contenente singola chiamata di Rails.logger.error:

Rails.logger.error "Some useful error message"

Codice spec:

expect(Rails.logger).to receive(:error).with(/error message/)

Se si desidera che il messaggio di errore venga effettivamente registrato mentre la specifica è in esecuzione, utilizzare il seguente codice:

expect(Rails.logger).to receive(:error).with(/error message/).and_call_original

Codice reale contenente più invocazioni di Rails.logger.error:

Rails.logger.error "Technical Error Message"
Rails.logger.error "User-friendly Error Message"

Codice spec:

    expect(Rails.logger).to receive(:error).ordered
    expect(Rails.logger).to receive(:error).with(/User-friendly Error /).ordered.and_call_original

Nota nelle impostazioni di variazione sopra .ordered è importante perché le altre aspettative cominciano a fallire.

Nel contesto di Rails ho verificato il codice sopra per funzionare come previsto comunque con info e debug livelli non sembra funzionare in modo diretto. Immagino sia a causa di Rails che usa internamente i livelli di debug e info che potrebbero causare errori come

(#<ActiveSupport::Logger:0x00000006c55778>).info(*(any args))
    expected: 1 time with any arguments
    received: 4 times with any arguments

Riferimenti:

http://www.relishapp.com/rspec/rspec-mocks/v/3-4/docs/setting-constraints/matching-arguments

http://www.relishapp.com/rspec/rspec-mocks/v/3-4/docs/setting-constraints/message-order


13
2017-12-15 14:36



Se il tuo obiettivo è quello di testare la funzionalità di registrazione, potresti anche considerare di verificare l'output su stream standard.

Ciò ti risparmierà il processo di derisione e testerà se i messaggi finiranno effettivamente dove dovrebbero (STDOUT / STDERR).

Con RSpec output matcher (introdotto in 3.0) puoi fare quanto segue:

expect { my_method }.to output("my message").to_stdout
expect { my_method }.to output("my error").to_stderr

Nel caso di librerie come Logger o Logging potresti doverlo usare output.to_<>_from_any_process.


1
2018-06-03 18:29