La première année des nouveaux diplômés a réfléchi à une méthode de mise en œuvre utilisant le TDD (ruby)

Pourquoi la première année des nouveaux diplômés a-t-elle prêté attention au TDD?

Travaille actuellement comme ingénieur dans la première année des nouveaux diplômés. J'avais peu d'expérience en ingénierie et je me demandais si je pourrais battre mes seniors en profitant de mon inexpérience.

Comme je suis inexpérimenté, je n'ai aucune habitude dans la procédure de montage. Parce que je n'ai pas d'habitude, j'ai décidé d'essayer de l'implémenter en utilisant TDD afin de prendre une bonne habitude (peut-être qu'il y avait une manière différente).

Ce que j'ai réellement fait

Qu'est-ce que TDD

Développement piloté par les tests. Avant l'implémentation, écrivez un test qui ne réussit que si l'implémentation réussit.

Image de TDD

Rédiger un test (avant l'implémentation) ↓ Le test échoue (car je n'ai rien implémenté) ↓ Implémenter ↓ Les tests réussissent (car l'implémentation vous permet de passer les tests que vous avez écrits avant l'implémentation) ↓ Refactor. Si ce test réussit, nous pouvons dire que nous avons pu corriger le code sans perdre de fonctionnalités. Au contraire, si le test échoue en raison du refactoring, la fonction qui aurait dû être implémentée a été perdue, donc déboguez-la.

Avantages et inconvénients du TDD

Avantages du TDD

Inconvénients du TDD

Indicateur de TDD

Afin de supprimer les inconvénients du TDD et d'en tirer parti, il est nécessaire d'avoir un index du moment à TDD.

En bref, vous pouvez essayer le TDD de base, mais si vous ne savez pas comment écrire un test, vous ne devriez pas faire de TDD.

Exemple spécifique de test lors du TDD

Voici un exemple concret de test avec TDD. L'explication utilise différents types de test (modèle, contrôleur, intégration, etc.), donc si vous n'êtes pas familier avec les types de test, veuillez jeter un œil ici. Structure du répertoire de test Rails et processus de test

Test simple

Succès sur demande ou vérification de l'existence des éléments requis (test simple du contrôleur). Il est bon d'écrire d'abord un test de confirmation simple

controller_test.rb


#Test du contrôleur
  test "should get home" do
    get root_path
    assert_response :success is #La demande aboutit-elle?
    assert_select "title", "HOME TITLE" #Le titre de la page est-il HOME TITLE?
  end

Validation

Commencez par écrire un test qui réussira si la validation réussit. (Exemple: test de modèle, test d'intégration pour vérifier le résultat de la transmission du formulaire)

user_test.rb


#Test du modèle utilisateur
#Ecrivez le test suivant avant de décrire le contenu de validation dans le modèle utilisateur
  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


#Nouveau test d'inscription(integration_test)je fais
#Un test que vous souhaitez échouer lors de la tentative d'enregistrement avec un paramètre qui devient invalide
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 pour la modification des fonctionnalités (débogage)

Il n'y a pas d'énoncé d'erreur particulier, mais écrivez d'abord le test lorsqu'il ne fonctionne pas comme prévu. Écrivez un test qui réussit uniquement lorsqu'il fonctionne comme vous le souhaitez, puis apportez des modifications au code pour qu'il fonctionne comme vous le souhaitez.

Le processus de déconnexion sera décrit à titre d'exemple. J'ai fait référence au Tutoriel Ruby on Rails 9.14 (Deux bogues peu visibles).

Login_controller.rb


class LoginController < ApplicationController
.
.
  
  def destroy #Action de déconnexion
    log_out
    redirect_to root_url
  end

  private #Désormais, la définition de la fonction utilisée dans l'action

  #Détruire une session persistante
  def forget(user)
    user.forget #Vider le jeton de mémoire de connexion de l'utilisateur stocké dans la base de données
    cookies.delete(:user_id) #Vider le contenu des cookies
    cookies.delete(:remember_token)
  end

  #Déconnectez l'utilisateur actuel
  #Courant indiquant l'utilisateur actuel_Vider le jeton de mémoire et la session de l'utilisateur,Courant variable_Vider le contenu de l'utilisateur
  def log_out
    forget(current_user) 
    session.delete(:user_id)
    current_user = nil
  end
end

Dans l'état de ce code, Ouvrez deux onglets dans votre navigateur et dans chaque onglet Supposons que vous soyez connecté avec le même utilisateur.

Tout d'abord, déconnectez-vous dans un onglet. Ensuite, la valeur de current_user devient nulle. Après cela, lorsque j'essaie de me déconnecter sur l'autre onglet, current_user est nul, donc il devient nil.forget et une erreur se produit.

Dans une telle situation, on peut dire qu '"il n'y a pas d'énoncé d'erreur particulier, mais cela ne fonctionne pas comme je m'y attendais", alors je fais TDD. Commencez par rédiger un test pour voir s'il fonctionne correctement lorsque vous vous déconnectez deux fois.

users_login_test.rb


def setup #Définir l'instance utilisateur pour se connecter
    @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
    #Simuler la déconnexion dans un autre onglet
    delete logout_path
    follow_redirect! #Lorsque vous redirigez, vérifiez s'il s'agit de la page avant de vous connecter
    assert_select "a[href=?]", login_path #Vérifiez s'il existe un chemin pour la page de connexion
    assert_select "a[href=?]", logout_path,      count: 0
    assert_select "a[href=?]", user_path(@user), count: 0
end

Apportez des modifications fonctionnelles pour réussir ce test. Enfin, ajoutez le code suivant et le test passera.

Login_controller.rb


class LoginController < ApplicationController
.
.
  
  def destroy #Action de déconnexion
    log_out if logged_in? #Utiliser la fonction de déconnexion uniquement dans l'état de connexion
    redirect_to root_url
  end
end

Conseils / autres

[Développement piloté par les tests](https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9 J'ai appris les astuces à utiliser lors de la mise en œuvre de TDD dans le livre% 96% 8B% E7% 99% BA-Kent-Beck / dp / 4274217884).

Dans ce livre, il était écrit qu'au moins la création de test-> l'implémentation provisoire-> la triangulation-> le refactoring devrait être fait.

Cette fois, je vais donner un exemple de TDD pour créer une fonction qui renvoie l'argument d'entrée (int) sous forme de chaîne de caractères.

Création de test minimum

Créez un test pour la fonction (pas encore créée). Au moment de la création, le test sera rouge.

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

Mise en œuvre temporaire

Définissez une fonction qui passera le test écrit ci-dessus sous n'importe quelle forme. Le test devient vert dans la définition de la fonction.

  def returnString(int)
    return "1"
  end

Levé triangulaire

Créez plusieurs tests du même type (deux cette fois) et réécrivez l'implémentation sous une forme générale pour que le test du Rera réussisse.

Lorsque je crée ce test, il devient rouge. Parce que l'implémentation actuelle ne renvoie que "1".

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

Passer d'une fonction qui renvoie une valeur brute de 1 à une fonction qui renvoie la valeur reçue en tant qu'argument sous forme de chaîne. Le test sera vert.

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

Refactoring

Même si vous faites TDD pour l'implémentation minimale comme décrit ci-dessus, le code deviendra compliqué à mesure que vous souhaitez ajouter d'autres fonctions. mais c'est d'accord. Grâce à l'écriture du test, vous pouvez juger avec précision la fonction du code. Par conséquent, vous pouvez refactoriser en toute confiance.

Ce que j'ai ressenti en pratiquant le TDD

users_signup_test.rb


#Tester une nouvelle inscription
#Un test que vous souhaitez échouer lors de la tentative d'enregistrement avec un paramètre qui devient invalide
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 que vous souhaitez réussir lors de la tentative d'enregistrement avec des paramètres valides
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       #Si le test réussit, vous savez que cette partie n'a pas été testée → Ecrivez le test pour que cette partie soit testée
      .
      .
    end
  end

Les références

Tutoriel Ruby on Rails [Développement piloté par les tests](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

La première année des nouveaux diplômés a réfléchi à une méthode de mise en œuvre utilisant le TDD (ruby)
[Ruby] Questions et vérification du nombre d'arguments de méthode
À propos du comportement de ruby Hash # ==
À propos du rôle de la méthode initialize