[RUBY] [R Spec on Rails] Comment écrire du code de test pour les débutants par les débutants

Cette fois, afin d'approfondir ma compréhension du code de test, je vais résumer comment écrire le code de test en utilisant RSpec. Quand j'ai écrit le code de test pour la première fois, je me souviens de l'avoir écrit en l'imitant sans savoir pourquoi j'avais besoin du code de test, alors j'aimerais revenir au début et l'écrire avec le plus de détails possible. À propos, une explication détaillée des termes est omise. Veuillez consulter l'article qui est résumé de manière simple à comprendre. Recommandé => Introduction à RSpec utilisable, partie 1 "Comprendre la syntaxe de base et les fonctions utiles de RSpec"

1. Pourquoi avez-vous besoin d'un code de test

Il s'agit de garantir la qualité en laissant le contrôle de fonctionnement de l'application à l'ordinateur. Si une personne vérifie manuellement le fonctionnement, une omission peut se produire. Vous pouvez éliminer l'erreur humaine en automatisant le test. Même s'il y a d'autres changements dans les spécifications, vous n'avez qu'à vérifier les changements, vous pouvez donc éviter de redémarrer tous les tests à partir de 1.

2. Qu'est-ce que Rspec?

RSpec est un joyau utilisé pour écrire du code de test pour Ruby on Rails. Ruby on Rails a une fonction de test standard appelée Minitest, mais sur le site de développement actuel utilisant Rails, les tests avec RSpec semblent être la norme, donc je l'utilise comme une pratique.

3. À propos du contenu de l'application à tester cette fois

Cette fois, nous avons trois modèles d'utilisateur, de salle et de message dans notre propre application de chat, et nous écrirons le flux du code de test pour chaque modèle d'utilisateur. Le but du code de test unitaire du modèle utilisateur est de vérifier si l'enregistrement de l'utilisateur est correct et si la validation d'ensemble fonctionne.

4. Environnement de développement

・ MacOS Catalina 10.15.6 ・ Rubis 2.6.5 ・ Rails 6.0.3 ・ Gem FactoryBot ・ Gem RSpec ・ Gem Faker

5. Procédure

5-0. Préparation

Tout d'abord, nous présenterons FactoryBot, RSpec et Faker.

Gemfile


(Abréviation)
group :development, :test do
  #Cette fois, nous utiliserons la dernière version, nous ne spécifions donc pas la version
  gem 'rspec-rails'
  #FactoryBot est utilisé pour créer automatiquement une instance. Vous n'êtes pas obligé, mais c'est aussi une pratique.
  gem 'factory_bot_rails'
  #Faker générera au hasard un nom et un mot de passe pour vous. C'est également pratique, alors habituons-nous-y.
  gem 'faker'
end
(Abréviation)

Effectuer l'installation du bundle

% bundle install
5-1. Paramètres RSpec

Créons les fichiers nécessaires pour RSpec.

% rails g rspec:install

Je pense que vous avez créé des fichiers.

create  .rspec
create  spec
create  spec/spec_helper.rb
create  spec/rails_helper.rb

Écrivez ce qui suit dans votre fichier .rspec

.rspec


--require spec_helper
--format documentation

Cette description vous permet de voir les résultats du code de test sur votre terminal. Exécutez la commande suivante pour créer un fichier pour tester le modèle utilisateur requis. Cette fois, seul le modèle User est utilisé, mais la procédure est la même pour les autres modèles.

% rails g rspec:model user

Vous devriez maintenant avoir les fichiers nécessaires.

create  spec/models/user_spec.rb
invoke  factory_bot
create spec/factories/users.rb

Si le fichier users.rb n'est pas créé, créez le répertoire factories dans le répertoire spec et créez le fichier users.rb dedans.

5-2. Paramètres FactoryBot

Nous allons mettre en place FactoryBot. Écrivez ce qui suit dans spec / factories / users.rb.

spec/factories/users.rb



#C'est une description de l'utilisation de FactoryBot
FactoryBot.define do
  #Classe d'utilisateur en écrivant comme suit(Modèle utilisateur)Il jugera automatiquement que
  factory :user do
    #Générer aléatoirement le contenu à enregistrer sous nom
    name {Faker::Name.first_name}
    #Générer automatiquement des e-mails
    email {Faker::Internet.email}
    #Pour le mot de passe, vous devez entrer la même valeur deux fois, y compris pour confirmation, donc générer aléatoirement la valeur sous forme de variable
    #Le mot de passe du périphérique doit comporter au moins 6 caractères, donc min_Définir la longueur à 6 caractères ou plus
    password = Faker::Internet.password(min_length: 6)
    #Définissez le mot de passe et la variable définie ci-dessus dans le cadre de confirmation du mot de passe
    password {password}
    password_confirmation {password}
  end
end

Cette fois, seuls le nom, l'adresse e-mail et le mot de passe sont disponibles, mais s'il existe d'autres éléments pour lesquels la validation est définie, veuillez les ajouter. Ceci termine les réglages de FactoryBot. Lançons la console dans le terminal et vérifions-la.

% rails c

[1] pry(main)> FactoryBot.build(:user)
=> #<User id: nil, name: "颯", email: "[email protected]", created_at: nil, updated_at: nil>

S'il s'agit d'une sortie comme celle-ci, c'est OK! (Le nom et l'e-mail sont générés aléatoirement par Faker, donc ils changent à chaque fois.)

5-3. Ecrire le code de test

Écrivons maintenant le code de test. Commencez par vérifier le fichier user_spec.rb.

spec/models/spec_user.rb


require 'rails_helper'

RSpec.describe User, type: :model do
- pending "add some examples to (or delete) #{__FILE__}"
+ describe '#create' do
+   before do
+     @user = FactoryBot.build(:user)
+   end
+ end
end

Tout d'abord, j'écrirai comme ça. Puisque décrire signifie expliquer, il décrit en quoi consiste le test. Créez une instance d'utilisateur basée sur le contenu défini dans le fichier spec / factories / users.rb dans le bloc après avant et en faire une variable. Puisqu'il sera utilisé dans une portée différente après cela, ce sera une variable d'instance.

De là, j'écrirai une brève explication dans le code

spec/models/spec_user.rb


RSpec.describe User, type: :model do
  #Créer un nouvel utilisateur(enregistrement)Parce que c'est un test à faire#Je crée
  describe '#create' do
    # spec/factories/user.Faire du contenu de rb une variable d'appel
    #Pas une variable locale car sa portée est différente@Pour en faire une variable d'instance
    before do
      @user = FactoryBot.build(:user)
    end
    #Décrivez la condition / situation en contexte
    context 'Si vous pouvez vous inscrire en tant qu'utilisateur' do
      #Décrivez l'article à tester
      it 'name, email, password, password_Si la confirmation est correctement saisie, vous pouvez vous enregistrer à nouveau' do
        #Si les informations utilisateur créées par FactoryBot sont correctes, elles ne seront pas validées et_réussir le test avec une
        expect(@user).to be_valid
      end
    end
  end
end

La syntaxe du code de test RSpec place souvent une condition après le contexte. Considérez le contenu de ce contexte comme la partie if (true) de l'instruction if ~ else. Par conséquent, on suppose que le contenu peut également être enregistré en tant qu'utilisateur. Décrivez ensuite les résultats attendus du test sous la forme expect (X) .to Y. Ce domaine est expliqué d'une manière très facile à comprendre dans l'article suivant.

Reference => Introduction à RSpec utilisable, Partie 1 "Comprendre la syntaxe de base et les fonctions utiles de RSpec" Cette fois, nous attendons le résultat que les informations utilisateur contenues dans la variable d'instance peuvent être nouvellement enregistrées sans être validées. Écrivez les détails de ce que vous voulez tester entre les ~ faire. Il est souhaitable que les autres voient de quoi il s'agit.

Vérifions si le résultat du test est correct. Entrez la commande suivante dans le terminal.

% bundle exec rspec spec/models/user_spec.rb 

Si ce qui suit est émis vers le terminal, il est correctement enregistré.

1 examples, 0 failure

Ensuite, nous testerons le cas où l'enregistrement n'est pas possible. Soit dit en passant, il y a un système normal et un système anormal dans le test, et le but initial qui confirme la fonction de l'objectif initial tel que l'enregistrement d'un nouvel utilisateur qui a testé en premier est le système normal, et inversement il ne peut pas être enregistré en raison de la validation. On appelle cela un système anormal pour s'assurer que ce qui précède ne peut pas être atteint. Après cela, nous testerons le système anormal.

Écrivons comme suit.

spec/models/user_spec.rb


 (Abréviation)
    context 'Si vous pouvez vous inscrire en tant qu'utilisateur' do
      #Décrivez l'article à tester
      it 'name, email, password, password_Si la confirmation est correctement saisie, vous pouvez vous enregistrer à nouveau' do
        #Si les informations utilisateur créées par FactoryBot sont correctes, elles ne seront pas validées et_réussir le test avec une
        expect(@user).to be_valid
      end
    end

    context 'Si vous ne pouvez pas vous inscrire en tant qu'utilisateur' do
      #Testé que l'enregistrement ne peut pas être effectué en raison de la validation lors de la tentative d'enregistrement sans entrer un nom d'utilisateur
      it 'Impossible de s'inscrire si le nom est vide' do
        #Mettre à jour le nom de l'utilisateur pour qu'il soit vide
        @user.name = nil
        # valid?Jugez s'il réussit la validation et, s'il échoue, générez un message d'erreur
        @user.valid? 
        # @user.errors.full_Afficher un message d'erreur avec des messages
        #Décrivez le message d'erreur affiché après inclure
        #Le nom peut si la devise n'est pas traduite en japonais'Je pense que vous obtiendrez le message d'erreur t être vide
        expect(@user.errors.full_messages).to include("Veuillez entrer un nom")
      end
    end

En bref, en définissant le nom sur nil et en utilisant la méthode? Valide, un message d'erreur dû à la validation est généré. Si Gem's'pry-rails 'est installé, écrivez binding.pry après user.valid?, Exécutez le code de test, et lorsque le processus s'arrête, entrez user.errors dans la console, et une erreur se produit. Vous pouvez également vérifier le message d'erreur en tapant user.erros.full_messages. À propos, si la chaîne de caractères dans l'inclusion du code ci-dessus est différente même d'un caractère, la sortie suivante sera sortie et le test ne passera pas.

Failures:

1) User#créer Si l'enregistrement de l'utilisateur n'est pas possible L'enregistrement n'est pas possible si le nom est vide
    Failure/Error: expect(@user.errors.full_messages).to include("Name can't be blank")
      expected ["Veuillez entrer un nom"] to include "Name can't be blank"
    # ./spec/models/user_spec.rb:28:in `block (4 levels) in <top (required)>'

Cela signifie que je m'attendais à ce que le message d'erreur soit "Le nom ne peut pas être vide", mais c'est en fait "Entrer le nom". (J'ai oublié que la devise était traduite en japonais et j'ai fait une erreur ...) Lors de la vérification de l'instruction d'erreur, le message d'erreur réel est émis après l'attente, donc si vous copiez et collez ceci, le test réussira.

Ceci est le code final.

spec/models/user_spec.rb


require 'rails_helper'

#Décrivez en quoi consiste le test Décrivez
#Cette fois, il s'agit d'un test du modèle User, donc ce sera comme ça
RSpec.describe User, type: :model do
  #Créer un nouvel utilisateur(enregistrement)Parce que c'est un test à faire#Je crée
  describe '#create' do
    # spec/factories/user.Faire du contenu de rb une variable d'appel
    #Pas une variable locale car sa portée est différente@Pour en faire une variable d'instance
    before do
      @user = FactoryBot.build(:user)
    end
    #Décrivez la condition / situation en contexte
    context 'Si vous pouvez vous inscrire en tant qu'utilisateur' do
      #Décrivez l'article à tester
      it 'name, email, password, password_Si la confirmation est correctement saisie, vous pouvez vous enregistrer à nouveau' do
        #Si les informations utilisateur créées par FactoryBot sont correctes, elles ne seront pas validées et_réussir le test avec une
        expect(@user).to be_valid
      end
    end

    context 'Si vous ne pouvez pas vous inscrire en tant qu'utilisateur' do
      #Testé que l'enregistrement ne peut pas être effectué en raison de la validation lors de la tentative d'enregistrement sans entrer un nom d'utilisateur
      it 'Impossible de s'inscrire si le nom est vide' do
        #Mettre à jour le nom de l'utilisateur pour qu'il soit vide
        @user.name = nil
        # valid?Jugez s'il réussit la validation et, s'il échoue, générez un message d'erreur
        @user.valid? 
        # @user.errors.full_Afficher un message d'erreur avec des messages
        #Décrivez le message d'erreur affiché après inclure
        #Le nom peut si la devise n'est pas traduite en japonais'Je pense que vous obtiendrez le message d'erreur t être vide
        expect(@user.errors.full_messages).to include("Veuillez entrer un nom")
      end

      it 'Impossible de s'inscrire si l'e-mail est vide' do
        @user.email = nil
        @user.valid?
        expect(@user.errors.full_messages).to include("Veuillez entrer votre email")
      end

      #Par défaut, devise a une validation que le même contenu d'unicité ne peut pas être enregistré.
      it 'Le même e-mail ne peut pas être enregistré s'il est déjà utilisé' do
        #Préparez deux utilisateurs pour confirmer l'unicité
        # @Enregistrer l'utilisateur
        @user.save
        #Créer un deuxième utilisateur
        another_user = FactoryBot.build(:user)
        # another_email de l'utilisateur@Mettre à jour avec le même e-mail que l'utilisateur
        another_user.email = @user.email
        another_user.valid?
        expect(another_user.errors.full_messages).to include("L'email existe déjà")
      end

      it 'Impossible de s'inscrire si le mot de passe est vide' do
        @user.password = nil
        @user.valid?
        expect(@user.errors.full_messages).to include("s'il vous plait entrez votre mot de passe", "Le mot de passe (pour confirmation) et l'entrée du mot de passe ne correspondent pas")
      end

      #Par défaut, l'appareil a une validation que vous ne pouvez pas enregistrer à moins que 6 caractères ou plus apparaissent dans le mot de passe
      it 'Impossible d'enregistrer si le mot de passe est de 6 caractères ou moins' do
        #Définir le mot de passe sur 5 caractères
        @user.password = "12345"
        @user.password_confirmation = "12345"
        @user.valid?
        expect(@user.errors.full_messages).to include("Veuillez saisir le mot de passe d'au moins 6 caractères")
      end:tired_face:

      it 'mot de passe même si le mot de passe est correct_Impossible de s'inscrire si la confirmation ne correspond pas' do
        # #Si vous définissez ce paramètre sur nul, il ne passera pas le test.""Doit être
        @user.password_confirmation = ""
        @user.valid?
        expect(@user.errors.full_messages).to include("Le mot de passe (pour confirmation) et l'entrée du mot de passe ne correspondent pas")
      end
    end
  end
end

Ce à quoi je n'ai pas pensé au début, c'est que je ne pouvais pas m'inscrire si mon adresse e-mail était la même que celle des autres utilisateurs. Le but était de créer d'abord deux utilisateurs et de mettre à jour la première adresse e-mail avec la même valeur que la deuxième adresse e-mail, intentionnellement la même.

Un autre point est la dernière partie, "Même si le mot de passe est correct, il ne peut être enregistré que si le mot de passe_confirmation correspond." Si vous définissez la confirmation du mot de passe sur nil, cela ne fonctionnera pas, vous devez donc indiquer explicitement qu'il est vide avec "". Au contraire, d'autres noms et e-mails peuvent être "".

Ce qui précède est le contenu du code de test unitaire du modèle User implémenté cette fois. J'ai essayé de l'écrire avec le plus de détails possible, mais c'est devenu assez long, mais la prochaine fois, j'aimerais que ce soit plus facile à comprendre. Ensuite, j'aimerais pouvoir écrire sur le code de test d'intégration. Je vous serais reconnaissant si vous pouviez signaler des erreurs ou des parties déroutantes.

Référence => FactoryBot Github Référence => RSpec Github Référence => Faker Github

Recommended Posts

[R Spec on Rails] Comment écrire du code de test pour les débutants par les débutants
Comment écrire des rails
Comment écrire du code de test avec la certification de base
[Pour les débutants Rails] Résumé de l'utilisation de RSpec (obtenir un aperçu)
[Ruby on Rails] Comment écrire enum en japonais
[Rails] Code de test à l'aide de Rspec
Comment écrire des graines de Rails
Comment écrire le routage Rails
[RSpec] Comment tester les messages d'erreur définis indépendamment par Shoulda-Matchers
Explication de Ruby on rails pour les débutants ④ ~ À propos des règles de dénomination et comment utiliser form_Tag ~
Comment utiliser Ruby on Rails
Comment déployer Bootstrap sur Rails
[Rails] Comment écrire la gestion des exceptions?
Comment rédiger un code facile à comprendre [Résumé 3]
Incontournable pour les débutants! Manière spécifique de gérer les projets X-code sur Github
Comprendre la couverture du code avec Rspec, le framework de test Ruby on Rails
[Ruby on Rails] Comment éviter de créer des routes inutiles pour concevoir
[Rails] Code de test unitaire pour le modèle utilisateur
Introduire RSpec et écrire le code de test unitaire
[Ruby on Rails] Afficher le test avec RSpec
[Ruby on Rails] Test du contrôleur avec RSpec
[Ruby] Comment utiliser slice pour les débutants
[Ruby on Rails] Comment utiliser redirect_to
Écrire du code difficile à tester
[Ruby on Rails] Test de modèle avec RSpec
Explication de Ruby sur rails pour les débutants ①
[SpringBoot] Comment écrire un test de contrôleur
[Pour les débutants] Comment déboguer avec Eclipse
Incontournable pour les débutants! Méthode spécifique pour gérer les projets X-code sur Github ②
Comment définir différentes versions source / cible pour le code de production et le code de test
(Pour les débutants) [Rails] Technologie de gain de temps! Comment installer et utiliser Slim
[Rspec] Flux de l'introduction de Rspec à l'écriture du code de test unitaire pour le modèle
[Rails] Comment décider de la destination par "voies ferrées"
Rails: comment bien écrire une tâche de râteau
[Java] Comment tester s'il est nul dans JUnit
[Rails] Comment écrire lors de la création d'une sous-requête
Comment sortir le CSV créé par Rails vers S3
JUnit 5: Comment écrire des cas de test dans enum
[Rails] Comment implémenter un test unitaire d'un modèle
[Pour les débutants] Comment implémenter la fonction de suppression
Présentation de Rspec, un framework de test pour Ruby on Rails
Comment séparer .scss par contrôleur dans Rails
Comment écrire du code qui pense Ruby orienté objet
[Rails MySQL] Comment réinitialiser la base de données sur heroku