Da Ruby auch für Klasse und Methode dynamischen Code generieren kann, kann dieser wie folgt geschrieben werden.
ARR = [true, false, true]
Class.new(Test::Unit::TestCase) do
ARR.each_with_index do |e, idx|
define_method "test_#{idx}" do
assert e
end
do
end
Dies ist gleichbedeutend mit dem Schreiben wie folgt.
ARR = [true, false, true]
class AnyTestCase < Test::Unit::TestCase
def test_0
assert ARR[0]
end
def test_1
assert ARR[1]
end
def test_2
assert ARR[2]
end
end
Es wird oft gesagt, dass sich der Testcode auf ** DAMP (beschreibende und aussagekräftige Sätze) ** und nicht auf DRY (nicht wiederholen) konzentrieren sollte.
Ich stimme dieser Angelegenheit grundsätzlich zu. Der Testcode sollte eine "Spezifikation" sein, und in diesem Sinne erscheint der gleiche Ausdruck viele Male in einer "in einer natürlichen Sprache geschriebenen Spezifikation", was aufgrund der Priorisierung der Klarheit unvermeidbar ist. Es versteht sich jedoch von selbst, dass das Gleichgewicht in allem wichtig ist.
Das Problem hier ist nun "Verifizierungsverarbeitung für eine große Datenmenge". Zum Beispiel gibt es so etwas
Lassen Sie uns den Umzug des Blogs ins Visier nehmen.
Wenn Sie ehrlich überprüfen, ob das Blog, in das Sie wechseln, mehr als ein Byte Inhalt im Tag "
require 'test/unit'
require 'httpclient'
require 'nokogiri'
class WebTestCase < Test::Unit::TestCase
def setup
@c = HTTPClient.new
end
def test_0
doc = Nokogiri::HTML(@c.get("https://example.com/entry/one").body)
assert_compare 1, "<", doc.css('article').text.length
end
def test_1
doc = Nokogiri::HTML(@c.get("https://example.com/entry/two").body)
assert_compare 1, "<", doc.css('article').text.length
end
def test_2
doc = Nokogiri::HTML(@c.get("https://example.com/entry/three").body)
assert_compare 1, "<", doc.css('article').text.length
end
end
Es ist subtil, dies auf "def test_1000" zu schreiben.
Da sich die Überprüfungsbedingung (assert_compare) nicht ändert, kann ich mir einen Plan vorstellen, die URL-Liste zu einem Iterator (Array) zu machen und sie wiederholt zu testen. Dies wird jedoch aus dem später beschriebenen Grund nicht empfohlen.
require 'test/unit'
require 'httpclient'
require 'nokogiri'
URLS = %w(
https://example.com/entry/one
https://example.com/entry/two
https://example.com/entry/three
)
class WebTestCase < Test::Unit::TestCase
def setup
@c = HTTPClient.new
end
def test_content_length
URLS.each do |url|
doc = Nokogiri::HTML(@c.get(url).body)
assert_compare 1, "<", doc.css('article').text.length
end
end
end
% w Notation ist praktisch. Nun, es sieht auf den ersten Blick gut aus. Das Problem tritt jedoch tatsächlich auf, wenn die Bestätigung fehlschlägt. Unten ist das Ergebnis der Ausführung, aber ** Ich weiß nicht, welche URL fehlgeschlagen ist **.
$ bundle exec ruby test_using_array.rb
Started
F
=========================================================================================================================================================================================
test_using_array.rb:25:in `test_content_length'
test_using_array.rb:25:in `each'
24: def test_content_length
25: URLS.each do |url|
26: doc = Nokogiri::HTML(@c.get(url).body)
=> 27: assert_compare 1, "<", doc.css('article').text.length
28: end
29: end
30: end
test_using_array.rb:27:in `block in test_content_length'
Failure: test_content_length(WebTestCase):
<1> < <0> should be true
<1> was expected to be less than
<0>.
=========================================================================================================================================================================================
Finished in 0.0074571 seconds.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 tests, 3 assertions, 1 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
0% passed
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Dies liegt daran, dass die Einheit des Tests jede Methode ist (def test_content_length
im obigen Beispiel).
Für jeden Iterator (Array) möchten wir für jeden Test eine Methode erstellen und darin testen. Gibt es keine andere Wahl, als es ehrlich durch Kopieren umzusetzen? Gibt es keine andere Wahl, als Code mit Hidemarus Makro zu generieren? Wenn Sie auf die Idee kommen, möchte ich Sie an die dynamische Codegenerierung erinnern, die die schwarze Magie (Metaprogrammierung) von Ruby ist.
Wie eingangs erwähnt, kann Ruby Code dynamisch generieren. Klasse und Methode sind keine Ausnahme. Sie können damit dynamisch nacheinander Testmethoden für den Inhalt des Iterators erstellen.
URLS = %w(
https://example.com/entry/one
https://example.com/entry/two
https://example.com/entry/three
)
Class.new(Test::Unit::TestCase) do
def setup
@c = HTTPClient.new
end
URLS.each_with_index do |url, idx|
define_method "test_#{idx}" do
doc = Nokogiri::HTML(@c.get(url).body)
assert_compare 1, "<", doc.css('article').text.length
end
end
end
Dieser Code entspricht dem folgenden Code, der der einfachen Implementierung entspricht.
URLS = %w(
https://example.com/entry/one
https://example.com/entry/two
https://example.com/entry/three
)
class AnyTestCase < Test::Unit::TestCase
def setup
@c = HTTPClient.new
end
def test_0
doc = Nokogiri::HTML(@c.get(URLS[0]).body)
assert_compare 1, "<", doc.css('article').text.length
end
def test_1
doc = Nokogiri::HTML(@c.get(URLS[1]).body)
assert_compare 1, "<", doc.css('article').text.length
end
def test_2
doc = Nokogiri::HTML(@c.get(URLS[2]).body)
assert_compare 1, "<", doc.css('article').text.length
end
end
Im folgenden Beispiel wird der Ort des Fehlers als "Fehler: test_2 ()" angegeben.
$ bundle exec ruby test_using_black_magic.rb
Loaded suite test_using_black_magic
Started
..F
=========================================================================================================================================================================================
test_using_black_magic.rb:27:in `block (3 levels) in <main>'
Failure: test_2():
<1> < <0> should be true
<1> was expected to be less than
<0>.
=========================================================================================================================================================================================
Finished in 0.007288 seconds.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 tests, 3 assertions, 1 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
66.6667% passed
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# each_with_index
hat einen Ursprung von 0. Ein Fehler in test_2 bedeutet einen Fehler, wenn der Wert "ARR [2]" ist. Sie sollten diesen Wert daher überprüfen.
--name
anzugebenWenn die Reihenfolge der im Iterator gespeicherten Werte garantiert ist, wird auch die Angabe mit "--name" unterstützt. Wenn Sie beispielsweise nur den Wert von "ARR [1]" testen möchten, geben Sie Folgendes an.
$ bundle exec ruby test_multiple.rb --name test_1
Der Schlüssel ist die dynamische Klassengenerierung durch "Class.new" und die dynamische Methodengenerierung durch "define_method". Wenn Sie daran interessiert sind, suchen Sie bitte nach "Ruby Black Magic".
Behauptung Dies gilt, wenn die Bedingungen einheitlich sind. Im Gegenteil, wenn sich die anzuwendende Behauptung in Abhängigkeit vom Eingabewert unterscheidet (= bedingte Verzweigung auftritt), ist es besser, sie ehrlich als DAMP zu implementieren.
Ich bin ein Amateur auf diesem Gebiet, daher weiß ich nicht, ob das zu mir passt.
EoT
Recommended Posts