Das erste Jahr der neuen Absolventen dachte über eine Implementierungsmethode nach, die TDD (Ruby) verwendet.

Warum hat das erste Jahr der neuen Absolventen auf TDD geachtet?

Derzeit arbeitet er als Ingenieur im ersten Jahr der neuen Absolventen. Ich hatte wenig Erfahrung im Ingenieurwesen und fragte mich, ob ich meine Senioren schlagen könnte, indem ich meine Unerfahrenheit ausnutzte.

Da ich unerfahren bin, habe ich keine Angewohnheit bei der Montage. Da ich keine Angewohnheit habe, habe ich beschlossen, es mit TDD zu implementieren, um eine gute Angewohnheit zu erhalten (vielleicht gab es einen anderen Weg).

Was ich tatsächlich getan habe

Was ist TDD?

Testgetriebene Entwicklung. Schreiben Sie vor der Implementierung einen Test, der nur erfolgreich ist, wenn die Implementierung erfolgreich ist.

Bild von TDD

Schreiben Sie einen Test (vor der Implementierung) ↓ Test schlägt fehl (weil ich nichts implementiert habe) ↓ Implementieren ↓ Tests sind erfolgreich (da Sie mit der Implementierung die Tests bestehen können, die Sie vor der Implementierung geschrieben haben) ↓ Refactor. Wenn der Test erfolgreich ist, können Sie den Code reparieren, ohne die Funktionalität zu verlieren. Im Gegenteil, wenn der Test aufgrund von Refactoring fehlschlägt, ist die Funktion, die implementiert werden sollte, verloren gegangen. Debuggen Sie sie daher.

Vor- und Nachteile von TDD

Vorteile von TDD

Nachteile von TDD

Anzeige für TDD

Um die Nachteile von TDD zu unterdrücken und auszunutzen, ist es erforderlich, einen Index darüber zu haben, wann TDD angewendet werden soll.

Kurz gesagt, es ist in Ordnung, einfaches TDD zu versuchen, aber wenn Sie nicht wissen, wie man einen Test schreibt, sollten Sie TDD nicht durchführen.

Spezifisches Testbeispiel bei TDD

Hier ist ein konkretes Beispiel für einen Test mit TDD. In der Erklärung werden verschiedene Testtypen (Modell, Controller, Integration usw.) verwendet. Wenn Sie die Testtypen nicht kennen, schauen Sie bitte hier. Rails-Testverzeichnisstruktur und Testprozess

Einfacher Test

Erfolg auf Anfrage oder Überprüfung auf Vorhandensein vorhandener Elemente (einfacher Controller-Test). Es ist gut, zuerst einen einfachen Bestätigungstest zu schreiben

controller_test.rb


#Controller-Test
  test "should get home" do
    get root_path
    assert_response :success is #Ist die Anfrage erfolgreich?
    assert_select "title", "HOME TITLE" #Ist der Titel der Seite HOME TITLE?
  end

Validierung

Schreiben Sie zuerst einen Test, der erfolgreich ist, wenn die Validierung erfolgreich ist. (Beispiel: Modelltest, Integrationstest zur Überprüfung des Ergebnisses der Formularübertragung)

user_test.rb


#Testen des Benutzermodells
#Schreiben Sie den folgenden Test, bevor Sie den Validierungsinhalt im Benutzermodell beschreiben
  def setup
    @user = User.new(name: "Example User", email: "[email protected]",
                     password: "hogehoge", password_confirmation: "hogehoge")
  end
  
  test "should be valid" do
    assert @user.valid? 
  end
  
  test "name should be present" do
    @user.name = "  "
    assert_not @user.valid?
  end
  
  test "email should be present" do
    @user.email = "  "
    assert_not @user.valid?
  end

users_signup_test.rb


#Neuer Registrierungstest(integration_test)ich mache
#Ein Test, den Sie fehlschlagen möchten, wenn Sie versuchen, sich mit einem ungültigen Parameter zu registrieren
test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
end

TDD zur Funktionsänderung (Debugging)

Es gibt keine bestimmte Fehleranweisung, aber schreiben Sie den Test zuerst, wenn er nicht wie erwartet funktioniert. Schreiben Sie einen Test, der nur dann besteht, wenn er wie gewünscht funktioniert, und nehmen Sie dann Änderungen am Code vor, damit er wie gewünscht funktioniert.

Der Abmeldevorgang wird als Beispiel beschrieben. Ich habe auf [Ruby on Rails Tutorial 9.14 (Zwei unauffällige Fehler)] verwiesen (https://railstutorial.jp/chapters/advanced_login?version=5.1#cha-advanced_login).

Login_controller.rb


class LoginController < ApplicationController
.
.
  
  def destroy #Aktion zum Abmelden
    log_out
    redirect_to root_url
  end

  private #Von nun an die Definition der in der Aktion verwendeten Funktion

  #Zerstören Sie eine dauerhafte Sitzung
  def forget(user)
    user.forget #Leeren Sie das in der Datenbank gespeicherte Anmeldespeichertoken des Benutzers
    cookies.delete(:user_id) #Leeren Sie den Inhalt von Cookies
    cookies.delete(:remember_token)
  end

  #Melden Sie den aktuellen Benutzer ab
  #Aktuell zeigt den aktuellen Benutzer an_Leeren Sie das Speichertoken und die Sitzung des Benutzers,Variabler Strom_Leeren Sie den Inhalt des Benutzers
  def log_out
    forget(current_user) 
    session.delete(:user_id)
    current_user = nil
  end
end

Im Status dieses Codes, Öffnen Sie zwei Registerkarten in Ihrem Browser und in jeder Registerkarte Angenommen, Sie sind als derselbe Benutzer angemeldet.

Melden Sie sich zunächst auf einer Registerkarte ab. Dann wird der Wert von current_user gleich Null. Wenn ich danach versuche, mich auf der anderen Registerkarte abzumelden, ist current_user nil, daher wird es nil.forget und es tritt ein Fehler auf.

In einer solchen Situation kann gesagt werden, dass "es keine bestimmte Fehleranweisung gibt, aber es funktioniert nicht wie erwartet", also mache ich TDD. Schreiben Sie zuerst einen Test, um festzustellen, ob er ordnungsgemäß funktioniert, wenn Sie sich zweimal abmelden.

users_login_test.rb


def setup #Definieren Sie die Benutzerinstanz, um sich anzumelden
    @user = User.new(name: "Example User", email: "[email protected]",
                     password: "hogehoge", password_confirmation: "hogehoge")
end

test "two times logout after login" do
    log_in(@user) 
    delete logout_path
    assert_not is_logged_in?
    assert_redirected_to root_url
    #Simulieren Sie das Abmelden auf einer anderen Registerkarte
    delete logout_path
    follow_redirect! #Überprüfen Sie beim Umleiten, ob es sich um die Seite handelt, bevor Sie sich anmelden
    assert_select "a[href=?]", login_path #Überprüfen Sie, ob ein Pfad für die Anmeldeseite vorhanden ist
    assert_select "a[href=?]", logout_path,      count: 0
    assert_select "a[href=?]", user_path(@user), count: 0
end

Nehmen Sie funktionale Änderungen vor, um diesen Test zu bestehen. Fügen Sie abschließend den folgenden Code hinzu, und der Test wird bestanden.

Login_controller.rb


class LoginController < ApplicationController
.
.
  
  def destroy #Aktion zum Abmelden
    log_out if logged_in? #Verwenden Sie die Abmeldefunktion nur im Anmeldestatus
    redirect_to root_url
  end
end

Tipps / Andere

[Testgesteuerte Entwicklung](https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9 Die Tipps zur Implementierung von TDD habe ich aus dem Buch% 96% 8B% E7% 99% BA-Kent-Beck / dp / 4274217884) gelernt.

In diesem Buch wurde geschrieben, dass zumindest die Testerstellung -> temporäre Implementierung -> Triangulation -> Refactoring durchgeführt werden sollte.

Dieses Mal werde ich ein Beispiel für TDD zum Erstellen einer Funktion geben, die das Eingabeargument (int) als Zeichenfolge zurückgibt.

Minimale Testerstellung

Erstellen Sie einen Test für die Funktion (noch nicht erstellt). Zum Zeitpunkt der Erstellung ist der Test rot.

  test "Pattern1 of test returnString function " do
    a = returnString(1)
    assert_equal a, "1"
  end

Vorübergehende Umsetzung

Definieren Sie eine Funktion, die den oben beschriebenen Test in beliebiger Form besteht. Der Test wird in der Funktionsdefinition grün.

  def returnString(int)
    return "1"
  end

Dreieckige Vermessung

Erstellen Sie mehrere Tests desselben Typs (diesmal zwei) und schreiben Sie die Implementierung in eine allgemeine Form, sodass der Test der Rera erfolgreich ist.

Wenn ich diesen Test erstelle, wird er rot. Weil die aktuelle Implementierung nur "1" zurückgibt.

  test "Pattern2 of test returnString function " do
    b = returnString(2)
    assert_equal b, "2"
  end

Wechseln Sie von einer Funktion, die einen Rohwert von 1 zurückgibt, zu einer Funktion, die den als Argument empfangenen Wert als Zeichenfolge zurückgibt. Der Test wird grün sein.

  def returnString(int)
    return "#{int}"
  end

Refactoring

Selbst wenn Sie TDD für die oben beschriebene Mindestimplementierung ausführen, wird der Code mit mehr Funktionen, die Sie hinzufügen möchten, kompliziert. aber es ist okay. Dank des Schreibens des Tests können Sie die Funktion des Codes genau beurteilen. Daher können Sie mit Vertrauen umgestalten.

Was ich fühlte, als ich TDD praktizierte

users_signup_test.rb


#Neue Registrierung testen
#Ein Test, den Sie fehlschlagen möchten, wenn Sie versuchen, sich mit einem ungültigen Parameter zu registrieren
test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
end

#Tests, die erfolgreich sein sollen, wenn Sie versuchen, sich mit gültigen Parametern zu registrieren
test "valid signup information" do
    get signup_path
    assert_difference 'User.count', 1 do
      post users_path, params: { user: { name:  "Example User",
                                         email: "[email protected]",
                                         password:              "password",
                                         password_confirmation: "password" } }
    end
end

controller


  def create
    if (user_id = session[:user_id])
      .
      .
    else
      raise       #Wenn der Test bestanden wurde, wissen Sie, dass dieses Teil nicht getestet wurde → Schreiben Sie den Test so, dass dieses Teil getestet wird
      .
      .
    end
  end

Verweise

Ruby on Rails Tutorial [Testgesteuerte Entwicklung](https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9 % 96% 8B% E7% 99% BA-Kent-Beck / dp / 4274217884) Clean code that works - How can we go there? - Takuto Wada | SeleniumConf Tokyo

Recommended Posts

Das erste Jahr der neuen Absolventen dachte über eine Implementierungsmethode nach, die TDD (Ruby) verwendet.
[Ruby] Fragen und Überprüfung der Anzahl der Methodenargumente
Über das Verhalten von Ruby Hash # ==
Informationen zur Rolle der Initialisierungsmethode