tests run rails matchers how describe ruby rspec

ruby - run - ¿Es posible que RSpec espere cambios en dos tablas?



shoulda-matchers (8)

Después de que ninguna de las soluciones propuestas demostró realmente funcionar, logré esto agregando un change_multiple matcher. Esto solo funcionará para RSpec 3 y no para 2. *

module RSpec module Matchers def change_multiple(receiver=nil, message=nil, &block) BuiltIn::ChangeMultiple.new(receiver, message, &block) end alias_matcher :a_block_changing_multiple, :change_multiple alias_matcher :changing_multiple, :change_multiple module BuiltIn class ChangeMultiple < Change private def initialize(receiver=nil, message=nil, &block) @change_details = ChangeMultipleDetails.new(receiver, message, &block) end end class ChangeMultipleDetails < ChangeDetails def actual_delta @actual_after = [@actual_after].flatten @actual_before = [@actual_before].flatten @actual_after.map.with_index{|v, i| v - @actual_before[i]} end end end end end

ejemplo de uso:

it "expects multiple changes despite hordes of cargo cultists chanting aphorisms" do a = "." * 4 b = "." * 10 times_called = 0 expect { times_called += 1 a += ".." b += "-----" }.to change_multiple{[a.length, b.length]}.by([2,5]) expect(times_called).to eq(1) end

Hacer que by_at_least y by_at_most funcionen para change_multiple requeriría un trabajo adicional.

RSpec espera un cambio:

it "should increment the count" do expect{Foo.bar}.to change{Counter.count}.by 1 end

¿Hay alguna manera de esperar cambios en dos tablas?

expect{Foo.bar}.to change{Counter.count}.by 1 and change{AnotherCounter.count}.by 1



Estoy ignorando las mejores prácticas por dos razones:

  1. Un conjunto de mis pruebas son pruebas de regresión, quiero que corran rápido y rara vez se rompen. La ventaja de tener claridad acerca de qué se está rompiendo exactamente no es enorme, y la desaceleración de la refacturación de mi código para que se ejecute el mismo evento varias veces es importante para mí.
  2. A veces soy un poco flojo, y es más fácil no hacer ese refactor

La forma en que hago esto (cuando tengo que hacerlo) es confiar en el hecho de que mi base de datos comienza vacía, entonces podría escribir:

foo.bar expect(Counter.count).to eq(1) expect(Anothercounter.count).to eq(1)

En algunos casos, mi base de datos no está vacía, pero conozco el recuento anterior o puedo probar explícitamente el recuento anterior:

counter_before = Counter.count another_counter_before = Anothercounter.count foo.bar expect(Counter.count - counter_before).to eq(1) expect(Anothercounter.count - another_counter_before).to eq(1)

Finalmente, si tiene que controlar muchos objetos (a veces lo hago), puede hacerlo como:

before_counts = {} [Counter, Anothercounter].each do |classname| before_counts[classname.name] = classname.count end foo.bar [Counter, Anothercounter].each do |classname| expect(classname.count - before_counts[classname.name]).to be > 0 end

Si tiene necesidades similares a mí, esto funcionará, mi único consejo sería hacer esto con los ojos abiertos: las otras soluciones propuestas son más elegantes, pero solo tienen un par de inconvenientes en ciertas circunstancias.


La mejor manera que he encontrado es hacerlo "manualmente":

counters_before = Counter.count another_counters_before = AnotherCounter.count Foo.bar expect(Counter.count).to eq (counters_before + 1) expect(AnotherCounter.count).to eq (another_counters_before + 1)

No es la solución más elegante, pero funciona


La sintaxis de Georg Ladermann es más agradable, pero no funciona. La forma de probar los cambios de valores múltiples es combinar los valores en matrices. De lo contrario, solo la última afirmación de cambio decidirá sobre la prueba.

Así es como lo hago:

it "should increment the counters" do expect { Foo.bar }.to change { [Counter.count, AnotherCounter.count] }.by([1,1]) end

Esto funciona perfectamente con la función ''.to''.


Prefiero esta sintaxis (rspec 3 o posterior):

it "should increment the counters" do expect { Foo.bar }.to change { Counter, :count }.by(1).and / change { AnotherCounter, :count }.by(1) end

Sí, estas son dos afirmaciones en un solo lugar, pero dado que el bloque se ejecuta solo una vez, puede acelerar las pruebas.

EDITAR: Se agregó una barra invertida después de .and para evitar el error de sintaxis


Recibí errores de sintaxis intentando usar la solución de @JohnJohnston ; esta es la forma que finalmente funcionó para mí:

it "should increment the counters" do expect { Foo.bar }.to change { Counter.count }.by(1) .and change { AnotherCounter.count }.by(1) end

Debo mencionar que estoy usando ruby ​​2.2.2p95. No sé si esta versión tiene algún cambio sutil en el análisis que me causa errores, pero no parece que nadie más en este hilo haya tenido ese problema.


Si no desea utilizar el enfoque basado en la taquigrafía / contexto sugerido anteriormente, también puede hacer algo como esto, pero tenga en cuenta que ejecutará la expectativa dos veces, por lo que podría no ser apropiado para todas las pruebas.

it "should increment the count" do expectation = expect { Foo.bar } expectation.to change { Counter.count }.by 1 expectation.to change { AnotherCounter.count }.by 1 end