2015-08-06 5 views
6

(bereits bei https://www.ruby-forum.com/topic/6876320 veröffentlicht, aber hier crossposted, weil ich bis jetzt keine Antwort erhalten habe).Ruby: Minitest, Test-Unit und Instanz-Variablen

Eine Frage, über Tests in Minitest und/oder Test :: Unit (das heißt die ordnungsgemäße Verwendung von parallelize_me!) Parallelisierung:

Angenommen, dass ich einige Hilfsmethoden haben, die von mehreren Tests benötigt werden. Von meinem Verständnis, konnte ich so etwas wie dies in einem solchen Verfahren (vereinfachtes Beispiel) nicht:

def prep(m,n) 
@pid = m 
@state = n 
end 

def process 
if @stat > 5 && @pid != 0 
    ... 
else 
    ... 
end 
end 

glaube ich das nicht in Minitest und Test-Gerät tun können, denn wenn ich rufe prep und Prozess aus einige meiner Testfunktionen, die Tests können nicht mehr parallelisiert werden - diese Testfunktionen setzen alle und lesen die gleiche Instanzvariable. Recht?

Nun, meine Frage ist, ob der folgende Ansatz wäre für Parallelisierung sicher sein: Ich alle diese wandelbar Instanzvariablen einen Hash zu machen, die ich im Setup wie folgt initialisiert:

def setup 
    @pid ||= {} 
    @state ||= {} 
end 

Meine „Hilfsmethoden "erhält einen Schlüssel (zum Beispiel des Namen der Tests Methode), und es verwendet, um die den Zugriff auf ihr‚eigenes‘Hashelement:

def prep(key,m,n) 
@pid[key] = m 
@state[key] = n 
end 

def process 
if @stat[key] > 5 && @pid[key] != 0 
    ... 
else 
    ... 
end 
end 

es ist ein bisschen hässlich, aber: ist das ein zuverlässiger Ansatz? Ist diese Art des Zugriffs auf einen Hash-Thread-Safe? Wie kann ich es besser machen?

Antwort

1

Mindestens in Minitest können Sie sicher tun, zum Beispiel,

setup do 
    @form = Form.new 
end 

ohne @form zwischen parallelen Tests verwechselt zu werden, so sollte dieser Ansatz sicher sein zu:

def setup 
    @stat = m 
    @pid = n 
end 

was bedeutet, dass Ihr ursprünglicher Ansatz sollte auch sicher sein.

================

UPDATE

betrachten das folgende GIST mit einem Stück Code, der 100 verschiedene Tests definieren @random Zugriff auf das gesetzt wird, in setuphttps://gist.github.com/bbozo/2a64e1f53d29747ca559

Sie werden feststellen, dass die in setup gesetzt Sachen nicht unter Tests geteilt werden, es vor jedem Test durchgeführt wird, im Grunde ist jeder Test gekapselt so Thread-Sicherheit ist kein Problem.

+0

Wie kann mein ursprünglicher Ansatz funktionieren?'setup' wird genau vor jedem Testfall aufgerufen, und die Instanzvariablen (@stat ...) werden zwischen den Testfällen geteilt. Wenn die Fälle parallel laufen (in mehreren Threads), haben wir eine Racebedingungen für die Instanzvariablen. – user1934428

+0

@ user1934428, hoffentlich hilft mein Update :) – bbozo

+0

Es tut in der Tat! Der von Ihnen geschriebene Quellcode beweist dies jedoch nicht. In den meisten Fällen ist die Ausgabe nur eine Folge von setup/test/setup/test/.... Selbst wenn die Variable unter Tests geteilt würde, würden Sie die Ausgabe erhalten. Die zwei Fälle, in denen die Ausgabe Setup/Setup/Test/Test ist, könnten vielleicht ein Artefakt der Ausgabepufferung sein. Ich habe mir die Freiheit genommen, Ihren Code ein wenig zu modifizieren, um diese Fälle auszuschließen, und der modifizierte Code beweist wirklich Ihre Aussage. – user1934428

0

Ihr Ansatz mit den Hashes macht Sinn, und es funktioniert, um zwischen den Threads zu unterscheiden. Das Problem liegt beim Global Interpreter Lock.

Sofern Ihre Hilfsmethoden IO-gebunden sind (HTTP-Anforderungen, Socket-Anforderungen, lokale Dateien verarbeiten), wird keine Geschwindigkeitsverbesserung angezeigt, da Ruby Ihren Code sequentiell über mehrere Threads ausführen wird , ohne eine garantierte Laufreihenfolge.

Viel Glück!