Die Programmiersprache Ruby

Blog|

Forum|

Wiki  


Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]

Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Autor Nachricht
BeitragVerfasst: 31 Mär 2008, 18:36 
Offline
Son-shi

Registriert: 23 Feb 2004, 14:59
Beiträge: 941
Wohnort: Esslingen
Hallo,
ich bin gerade am Einsteigen und erproben von Test::Unit.

Hier mal ein Programmschnipsel wie ich es verwenden will. Kommentare über Sinn und Unsinn und wie ich es besser machen kann sind willkommen und erwünscht.

Zum Hintergrund:
Ich will Tests für einen Dokumentengenerierer aufbauen. Ich kann zwar Detailtests machen, bin aber schnell an dem Punkt wo es (IMHO) unsinnig wird.
Ein assert_equal ist zwar schön und gut für kurze Ergebnisse, aber ich habe teilweise längere Texte die ich prüfen will. Und bei Abweichungen muss ich ziemlich lange suchen, bis ich den Unterschied entdecke.

Und da mein Ziel sowieso die Dateierzeugung ist, dachte ich mir, ich Vergleiche mit Dateien.

Der Code:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
require 'test/unit'
require 'ftools'
class Test::Unit::TestCase
#
#Takes the content of the file 'filename' and compares it with 'actual' like in assert_equal.
#If 'filname' doesn't exist, the failure
# Reference file <#{filename}> missing
#is returned.
#
#'folder_for_failure' will contain all results with differences.
#
#Recommendation to build up your test.
#1) Create two folders: 'expected' and 'failure'
#2) Define your assertion with a non-existing filename
#3) Run the test with folder_for_failure = 'failure'
#4) You will get a failure (filename is missing).
#5) Copy the file in 'failure' to 'expected'
#6) Rerun again, you hav no failure (hopefully ;-) )
def assert_equal_filecontent( filename, actual, folder_for_failure = nil, message = nil )
if File.exist?(filename)
expected = File.readlines(filename).to_s
full_message = build_message(message, "<?> expected (#{filename}) but was\n<?>.\n", expected, actual)
else
full_message = "Reference file <#{filename}> missing"
end
#Write the real result to a file.
#Folder is defined with Test::Unit::TestCase#folder_for_failure
if folder_for_failure and expected != actual
File.makedirs(folder_for_failure) if ! File.directory?(folder_for_failure)
File.open( "#{folder_for_failure}/#{File.basename(filename)}", 'w'){|f|
f << actual
}
end
assert_block( full_message ){ expected == actual }
end
#
end

class MyTest < Test::Unit::TestCase
def test_myblock()
folder_for_failure = 'failure'
assert_equal_filecontent( 'expected/test.yaml', ['aaa'].to_yaml, folder_for_failure )
assert_equal_filecontent( 'expected/test2.yaml', {1=> 'eins', 2 => 'zwei'}.to_yaml, folder_for_failure)
end
end


Mein Vorgehen:
  • Ich habe einen Ordner 'expected' in dem ich meine Referenzdokumente ablege.
  • Jetzt baue ich meine assertions mit assert_equal_filecontent auf.
    Dabei übergebe ich den Dateinamen meiner 'korrekten' Datei.
  • assert_equal_filecontent liest die Referenzdatei ein und vergleicht mit dem neu erzeugten Inhalt.
  • Bei Abweichungen wird im Ordner 'failure' eine Datei mit den erzeugten Inhalt angelegt.
  • Der Test meldet die Abweichung und ich kann mit einem diff die Dateien vergleichen.
Je nach Ergebnis kann ich mein Programm anpassen bis der Inhalt passt, oder ich übernehme die Datei im failure-Ordner als neue Referenz.

Beim Ordner zum speichern der Abweichung bin ich noch nicht ganz glücklich. Da bin ich noch am überlegen, ob ich die nicht einmal zentral definieren soll.

Evtl. brauche ich später noch ein assert_similar_filecontent, in dem ich zusätzliche Regeln einbaue, wann zwei Files identisch sind (z.B. Zeitstempel entfernen)

_________________
http://ruby.lickert.net/
http://gems.rubypla.net/


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 31 Mär 2008, 19:35 
Offline
Interpreter

Registriert: 29 Okt 2002, 14:25
Beiträge: 2137
Wie bereits vor kurzem an anderer Stelle hingeweisen wurde, kann man File.readlines(filename).to_s besser durch File.read(filename) ersetzen. Das ist zum einen direkter und damit besser lesbar, und zum anderen auch effizienter, da der Aufbau des temporären Arrays wegfällt!

Ansonsten habe ich mal was ähnliches gemacht und dabei die MD5-Prüfsummen der betroffenen Dateien verglichen, was (vor allem bei sehr großen Dateien) sehr effizient ist. Allerdings haben mich konkrete Unterschiede auch nicht interessiert, ich wollte nur sicherstellen, dass eine Datei nicht geändert wurde.

Gruß
janfri

_________________
Ruby-Mine

"Simplicity is the ultimate sophistication." Leonardo da Vinci


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 31 Mär 2008, 19:53 
Offline
Son-shi

Registriert: 23 Feb 2004, 14:59
Beiträge: 941
Wohnort: Esslingen
janfri hat geschrieben:
Wie bereits vor kurzem an anderer Stelle hingeweisen wurde, kann man File.readlines(filename).to_s besser durch File.read(filename) ersetzen.

Ich hoffe ich krieg das endlich mal in meinen Kopf rein. Als ich mit File.open anfing dachte ich, da war doch was, das das kürzer geht. Es geht noch kürzer :oops:
Danke!

_________________
http://ruby.lickert.net/
http://gems.rubypla.net/


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 31 Mär 2008, 20:25 
Offline
Interpreter

Registriert: 10 Dez 2007, 17:37
Beiträge: 1906
Wenn du einen richtigen diff brauchst, dann kannst du dir ja mal dies hier ansehen

_________________
Grüße
Jack


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 31 Mär 2008, 20:31 
Offline
Interpreter

Registriert: 10 Dez 2007, 17:37
Beiträge: 1906
Edit:

Wenn es dir um das sparen von Code-Zeilen geht dann:

statt

assert_block( full_message ){ expected == actual }

=>

assert_equal(expected, actual, full_message)

würde 2 Klammern und == sparen, wenn das möchtest.



1
2
3
4
5
6
  full_message = if File.exist?(filename)
expected = File.readlines(filename).to_s
build_message(message, "<?> expected (#{filename}) but was\n<?>.\n", expected, actual)
else
"Reference file <#{filename}> missing"
end

_________________
Grüße
Jack


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 03 Mai 2008, 21:53 
Offline
Son-shi

Registriert: 23 Feb 2004, 14:59
Beiträge: 941
Wohnort: Esslingen
Mir fiel auf das ich vergessen habe eine Rückmeldung zu geben.

Danke für die Tipps.

@slowjack2k: diff selbst war weniger mein Problem, das löse ich Ruby-extern durch andere vergleicher. Mir war nur wichtig zu erkennen, das ein Unterschied vorliegt - und ich dann anderweitig vergleichen kann.

Und das sparen von Code ist mir nicht so wichtig.

Ich habe mein Code inzwischen bei den Machern von test/unit als Vorschlag eingereicht:
http://rubyforge.org/tracker/?func=deta ... atid=21859

_________________
http://ruby.lickert.net/
http://gems.rubypla.net/


Nach oben
 Profil  
 
BeitragVerfasst: 07 Feb 2010, 23:51 
Offline
Son-shi

Registriert: 23 Feb 2004, 14:59
Beiträge: 941
Wohnort: Esslingen
Sorry das ich das alte Posting ausgrabe. Ich bin gerade bei einer Google-Recherche zufällig darauf gestoßen.

Zur Info: Ich habe den Coding-Schnippsel inzwischen als ein gem veröffentlicht:

_________________
http://ruby.lickert.net/
http://gems.rubypla.net/


Nach oben
 Profil  
 
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
cron