4 Stimmen

Mocking-Konstruktoren in Ruby

Ich bin ein Java-Entwickler, der mit Ruby herumspielt, und ich liebe es. Ich habe verstanden, dass meine Unit-Tests dank der Metaprogrammiermöglichkeiten von Ruby viel sauberer werden und ich keine lästigen Mocking-Frameworks brauche. Ich habe eine Klasse, die die File Klasse und in meinem Test möchte ich mein echtes Dateisystem nicht berühren. In Java würde ich ein virtuelles Dateisystem für einfachere "Nähte" verwenden, um Fake-Objekte zu übergeben, aber in Ruby ist das offensichtlich ein Overkill. Was ich mir ausgedacht habe, sieht im Vergleich zur Java-Welt schon sehr gut aus. In meiner zu testenden Klasse habe ich einen optionalen Konstruktorparameter:

def initialize(file_class=File)

Wenn ich in meiner Klasse Dateien öffnen muss, kann ich dies dann tun:

@file_class.open(filename)

Und der Aufruf geht entweder an die echte File-Klasse, oder im Falle meines Unit-Tests an eine Fake-Klasse, die das Dateisystem nicht berührt. Ich weiß, es muss ein besserer Weg, dies mit Metaprogrammierung zu tun sein?

12voto

Brian Phillips Punkte 12277

Mokka ( http://mocha.rubyforge.org/ ) ist eine sehr gute Mocking-Bibliothek für Ruby. Je nachdem, was Sie eigentlich testen wollen (z.B. wenn Sie nur den Aufruf von File.new vortäuschen wollen, um die Abhängigkeit vom Dateisystem zu vermeiden, oder wenn Sie überprüfen wollen, ob die richtigen Argumente an File.new übergeben werden), könnten Sie so etwas tun:

require 'mocha'

mock_file_obj = mock("My Mock File") do
  stubs(:some_instance_method).returns("foo")
end

File.stubs(:new).with(is_a(String)).returns(mock_file_obj)

1voto

tomafro Punkte 5718

In dem von Ihnen geschilderten Fall würde ich sagen, dass das, was Sie tun, in Ordnung ist. Ich weiß, dass es eine Technik ist, die James Mead (der Autor von Mocha) befürwortet hat. Es gibt keinen Grund, Metaprogrammierung nur um ihrer selbst willen zu betreiben. Hier ist, was James dazu zu sagen hat (und eine lange Liste anderer Techniken, die Sie ausprobieren könnten)

1voto

Mulan Punkte 117501

Dies ist für mich eine besonders schwierige Herausforderung. Mit der Hilfe, die ich bei diese Frage und einiger zusätzlicher Arbeit meinerseits, habe ich folgende Lösung gefunden.

# lib/real_thing.rb
class RealThing
  def initialize a, b, c
    # ...
  end
end

# test/test_real_thing.rb
class TestRealThing < MiniTest::Unit::TestCase

  class Fake < RealThing; end

  def test_real_thing_initializer
    fake = mock()
    Fake.expects(:new).with(1, 2, 3).returns(fake)
    assert_equal fake, Fake.new(1, 2, 3)
  end

end

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X