2010-07-28 10 views
11

To jest pytanie dotyczące najlepszej praktyki. Są na to oczywiste sposoby, żadne z nich nie wydaje się całkiem słuszne.Struny wielowierszowe z nacięciem w rublu

Bardzo często muszę przetestować, że powstaje ciąg wielowierszowy. Zwykle łamie wcięcia czyni wszystko wyglądać bałagan:

class TestHelloWorld < Test::Unit::TestCase 
    def test_hello 
    assert_equal <<EOS, hello_world 
Hello, world! 
    World greets you 
EOS 
    end 
end 

Z <<- mogę wciąć tu marker doc, ale nie pozbawić wcięcia wewnątrz heredoc, to nadal wygląda okropnie.

class TestHelloWorld < Test::Unit::TestCase 
    def test_hello 
    assert_equal <<-EOS, hello_world 
Hello, world! 
    World greets you 
    EOS 
    end 
end 

To pozwala mi na wcięcie, ale czytelność cierpi na linii testowej. Ten gsub naprawdę nie jest tutaj właściwy.

class TestHelloWorld < Test::Unit::TestCase 
    def test_hello 
    assert_equal <<-EOS.gsub(/^ {6}/, ""), hello_world 
     Hello, world! 
     World greets you 
    EOS 
    end 
end 

Czy istnieje sposób na przetestowanie takich wielowierszowych łańcuchów, które są naprawdę czytelne?

+1

Te dwie odpowiedzi: http://stackoverflow.com/a/3772911/17305 http://stackoverflow.com/a/5638187/17305 może być alternatywą dla przyjętego odpowiedź, jeśli chcesz uniknąć zależności zewnętrzne . Przenoszą 'gsub' poza pole widzenia, łatając' String', pozostawiając tekst tutaj bardziej czytelny. – Synoli

Odpowiedz

7

Osobiście uważam, że rubinowe wcięte heredocs są bezużyteczne i powinny działać bardziej jak Bash wcięty heredoc, a także usuwać białe znaki wewnątrz the string & hellip;

W każdym razie istnieje kilka bibliotek, które próbują poradzić sobie z tą sytuacją.Istnieje szeroki wachlarz bibliotek, które próbują rozwiązać ten problem:

0

Nie jestem pewien, każdy z nich można nazwać „Best Practice”, ale tutaj są cztery możliwości

class Hello 

    def self.world 
"Hello, world! 
    World greets you 
" 
    end 
end 

require 'test/unit' 

class TestHelloWorld < Test::Unit::TestCase 

#Define a constant array of multiline strings and test against the array 
# see test_hello_4 
# Alternatively store the multi-line strings in a Yaml fixture file and load 
# them into a constant Hash or Array within a setup method 
MLINE = [ 
"Hello, world! 
    World greets you 
", 
"Another multi line string", 
    ] 

    # Create a method to return the string 
    def test_hello_1 
    assert_equal Hello.world, hello_world_string() 
    end 

    # Create the string using embedded newlines 
    def test_hello_2 
    assert_equal Hello.world, "Hello, world!\n World greets you\n" 
    end 

    # if you only have 1 in the test then put it in a DATA section 
    def test_hello_3 
    assert_equal Hello.world, DATA.read 
    end 

    def test_hello_4 
    assert_equal Hello.world, MLINE[0] 
    end 

    def hello_world_string 
"Hello, world! 
    World greets you 
" 
    end 
end 

__END__ 
Hello, world! 
    World greets you 

Wszystko przechodząc

Loaded suite test_hello_world 
Started 
.... 
Finished in 0.00083 seconds. 

4 tests, 4 assertions, 0 failures, 0 errors 

ja osobiście wolę ciąg z osadzonymi znakami nowej linii (Metoda 2), chyba że ciąg był bardzo długi, w którym to przypadku skorzystałbym z sekcji DATA.

0

Czy jest to test na temat formatowania lub treści?

Jeśli jest to test dotyczący formatowania, być może twój test jest zbyt wysoki i powinieneś przetestować klasę "Formatter", a prawdopodobnie znajdziesz sposób na przetestowanie klasy w taki sposób, że porównywanie tekstu wielowierszowego jest bezużyteczne. . A wtedy będziesz mógł kpić z klasy Formatter, aby sprawdzić, czy otrzyma całą potrzebną zawartość. Na przykład Formatter może być klasą, która ma metodę add_line, która dodaje "\ n" po każdym argumencie, który podano, i sformatowany_string, który zwróci ciąg wielowierszowy. Po przetestowaniu klasy Formatter musisz po prostu sprawdzić, czy jest poprawnie wywoływana. W ten sposób oddzielasz testy treści od testów dla formatu.

Jeśli jest to test dotyczący zawartości, może powinieneś podzielić hello_world po linii, a następnie sprawdzić, czy pierwszy wiersz zawiera słowo "Hello, world", a drugi zawiera słowo "World welcome you".

Nie sądzę, że to dobra praktyka w ogóle do testowania całego bloku wielowierszowego tekstu.

+0

Testowanie wszystkiego naraz jest jedynym właściwym sposobem. Jeśli się różni - test powinien pokazać cały oczekiwany wynik i cały faktyczny wynik. Porównywanie linii po linii i takie właśnie sprawiają, że raporty o błędach z testów są bezwartościowe. – taw

+0

Jak mówię w mojej odpowiedzi, to naprawdę zależy od tego, co testujesz: zawartość lub format? Jeśli naprawdę chcesz przetestować oba w tym samym czasie, myślę, że inni już dali dobre odpowiedzi. – David

9

Jeśli tworzysz aplikację Rails, spróbuj użyć strip_heredoc, jeśli nie, zawsze możesz wymagać aktywnych rozszerzeń core_support.

Twój przykład może wyglądać następująco:

require 'active_support/core_ext' 

class TestHelloWorld < Test::Unit::TestCase 
    def test_hello 
    assert_equal <<-EOS.strip_heredoc, hello_world 
     Hello, world! 
     World greets you 
    EOS 
    end 
end 

Jeśli naprawdę nie chcesz je zawierać następujący kod jest skopiowany z active_support jak i przykładem, jak można poradzić sobie z formatowania.

class String 
    def try(*a, &b) 
    if a.empty? && block_given? 
     yield self 
    else 
     __send__(*a, &b) 
    end 
    end 

    def strip_heredoc 
    indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0 
    gsub(/^[ \t]{#{indent}}/, '') 
    end 
end