2017-07-23 1 views
0

Ich habe eine einfache Klasse:Erwartet Lambdas in RSpec

class Maybe 
    def initialize(value, maybe_klass = Maybe) 
    @value = value 
    @maybe_klass = maybe_klass 
    end 

    attr_reader :value 

    def map(function) 
    return self if value.nil? 
    return maybe_klass.new(compose(value, function)) if value.is_a? Proc 
    maybe_klass.new(function.curry.call(*value)) 
    end 

    private 

    attr_reader :maybe_klass 

    def compose(f, g) 
    lambda { |*args| f.call(g.call(*args)) } 
    end 
end 

Ich versuche es so zu testen:

it 'creates a new wrapped function that does both of the functions combined' do 
    maybe_double = double Maybe 
    add_four = ->(x) { x + 4 } 
    maybe = Maybe.new(add_four, maybe_double) 
    composed_lambda = ->(*args) { maybe.value.call(add_four.call(*args)) } 
    expect(maybe_double).to receive(:new).with(composed_lambda) 
    maybe.map(add_four) 
end 

Dieser Test nicht undefined method '+' for #<Proc:0x007fdd0b269e78>

Ich denke nicht Work- Das komponierte Lambda wird ausgewertet, bevor ich es brauche, aber ich bin mir nicht sicher. Was soll ich erwarten, dass die Methode initialize des Doppels mit aufgerufen wird? Ist das überhaupt der richtige Weg, diese Klasse zu testen? Ich habe das Gefühl, dass ich die Interna der Klasse mit der composed_lambda Variable zu sehr nachmache, aber ich bin mir nicht sicher, was ich stattdessen erwarten sollte.

Da die Funktion eine neue Instanz der Klasse, die wir testen, zurückgibt, ist es nicht wirklich möglich, diese ganze Klasse zu stubben - wir werden am Ende versuchen, das getestete System zu stubben.

Antwort

2

Es scheint, dass Sie den richtigen Code haben, aber Sie erwarten, dass rspec anders funktioniert. Hier ist die issue about it

rspec verwenden === Erwartungen zu überprüfen, aber in ruby wenn Sie === Betreiber auf lambda verwenden, werden die Lambdas genannt. Wenn Sie also ein Lambda in receive(:new).with Methode übergeben, ruft rspec dieses Lambda mit einem Argument, dass Maybe#new Methode erhalten.

Für Ihren Fall würde ich vorschlagen, für Sie Tests dieses coole Feature mit:

it 'creates a new wrapped function that does both of the functions combined' do 
    maybe_double = double Maybe 
    add_four = ->(x) { x + 4 } 
    maybe = Maybe.new(add_four, maybe_double) 
    expect(maybe_double).to receive(:new).with(lambda { |composed_lambda| 
    expect(composed_lambda.(4)).to eq 12 
) 
    maybe.map(add_four) 
end 

Also, Sie überprüfen, ob das Lambda dass Maybe#new erhielt ein bestandenes Lambda und wende die Zusammensetzung auf dem Wert . Das ist, weil Sie zwei Lambda nicht vergleichen können, bis Sie sie anrufen.

Ich hoffe, es hilft.

+0

Es sieht so aus, als würde ich 'receive (: new) {composed_lambda}' bekommen, wird der Block einfach ignoriert, also testet er nur, dass new aufgerufen wird. Was sich wie ein schwacher Test anfühlt, da es viele Wege gibt, die passieren könnten, ohne das Verhalten zu bekommen, nach dem ich suche – Adzz