[RUBY] # 4 post-validation et mise en œuvre de test pour créer une API de tableau d'affichage avec certification et autorisation dans Rails 6

Création d'une API de tableau d'affichage avec autorisation de certification avec Rails 6 # 3 RSpec, FactoryBot est introduit et un modèle de publication est créé

Écrire un test de modèle avec RSpec

Pour le moment, j'ai pu confirmer que la création et la lecture fonctionnent la dernière fois. De là, suivez cette procédure

  1. Rédigez un modèle de test pour la publication
  2. Mettre en œuvre la validation
  3. Ecrire un test post-contrôleur
  4. Ecrire le contrôleur et les routes
  5. Écrivez la graine

Dans cet article, je vais implémenter 1 et 2 pour le moment, et après 3. je vais passer aux articles suivants et suivants.

Écraser le rubocop à l'avance

Écrire un document Excluez l'erreur telle qu'elle apparaît dans le fichier de migration.

.rubocop.yml peut être exclu de cette manière, mais si vous excluez ce dont vous avez besoin à l'origine, cela brisera le sens de l'observation des normes de codage en premier lieu, alors discutons-en fermement lors de l'ajout dans le développement d'équipe. ..

diff:.rubocop.yml


+ #Documentation
+ Style/Documentation:
+  Exclude:
+    - "db/migrate/**/*"
...

Commencez par écrire un test de modèle

Comme Test Driven Development (TDD), le premier est le test de Red. Puisque la validation n'est pas implémentée, je vais faire quelque chose qui sera rouge même si j'écris un test et l'exécute.

Je vais l'écrire dans une coche Rails normale sans utiliser une seule fois factory_bot.

spec/models/post_spec.rb


# frozen_string_literal: true

require "rails_helper"

RSpec.describe Post, type: :model do
  describe "subject" do
    context "Lorsque vide" do
      it "Devenir invalide" do
        post = Post.new(subject: "", body: "fuga")
        expect(post).not_to be_valid
      end
    end
  end
end

Donc, le code ci-dessus teste que "il devient invalide lorsque le sujet est vide". Mais jusqu'à présent, je n'ai pas validé le sujet du modèle de publication, donc le message est valide et le test "invalide" échouera.

$ rspec spec/models/post_spec.rb
...
Finished in 0.07805 seconds (files took 3.53 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/models/post_spec.rb:8 #Non valide lorsque le sujet du message est vide

ec2-user:~/environment/bbs (master) $ rspec

Essayons de nous inscrire même si le sujet est vide.

$ rails c
[1] pry(main)> Post.create!(subject: "", body: "hoge")
   (0.1ms)  BEGIN
  Post Create (2.5ms)  INSERT INTO "posts" ("subject", "body", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["subject", ""], ["body", "hoge"], ["created_at", "2020-09-06 01:07:52.628768"], ["updated_at", "2020-09-06 01:07:52.628768"]]
   (0.9ms)  COMMIT
=> #<Post:0x0000000005760700
 id: 2,
 subject: "",
 body: "hoge",
 created_at: Sun, 06 Sep 2020 01:07:52 UTC +00:00,
 updated_at: Sun, 06 Sep 2020 01:07:52 UTC +00:00>

Vous l'avez sauvegardé.

Au fait, sans utiliser de description ni de contexte

spec/models/post_spec.rb


# frozen_string_literal: true

require "rails_helper"

RSpec.describe Post, type: :model do
  it "Invalide lorsque le sujet est vide" do
    post = Post.new(subject: "", body: "fuga")
    expect(post).not_to be_valid
  end
end

Le comportement du code de test est presque le même. C'est parce que vous pouvez tester en écrivant expect dans le bloc it. Cependant, il devient difficile à comprendre lors de la description de la même colonne et des mêmes conditions de validation par regroupement, il est donc fondamentalement recommandé de décrire en imbriquant la description et le contexte.

Ajouter une validation au modèle

Validation avec un blanc comme erreur

app/models/post.rb


 class Post < ApplicationRecord
+  validates :subject, presence: true
 end

Vous ne pouvez plus vous inscrire avec vrai ou vide pour la présence de la colonne sujet.

Essayons.

$ rails c
[1] pry(main)> Post.create!(subject: "", body: "hoge")
ActiveRecord::RecordInvalid: Validation failed: Subject can't be blank
from /home/ec2-user/.rvm/gems/ruby-2.7.1/gems/activerecord-6.0.3.2/lib/active_record/validations.rb:80:in `raise_validation_error'

Je ne peux pas m'inscrire.

$ rspec ./spec/models/post_spec.rb 
...
Finished in 0.05053 seconds (files took 1.63 seconds to load)
1 example, 0 failures

Le test a également réussi.

Validation du nombre maximum de caractères

Comme ce serait un problème si le nombre de caractères pouvait être enregistré indéfiniment, nous ajouterons une limite. C'est aussi le premier test. J'écrirai un test avec un plan pour ajouter la validation qu'il est OK s'il est de 30 caractères ou moins et NG s'il est de 31 caractères ou plus.

spec/models/post_spec.rb


         expect(post).not_to be_valid
       end
     end
+    context "par maxlength" do
+      context "Pour 30 caractères" do
+        it "Devenir valide" do
+          post = Post.new(subject: "Ah" * 30, body: "fuga")
+          expect(post).to be_valid
+        end
+      end
+      context "Pour 31 caractères" do
+        it "Devenir invalide" do
+          post = Post.new(subject: "Ah" * 31, body: "fuga")
+          expect(post).not_to be_valid
+        end
+      end
+    end
   end
 end

Faisons un test.

$ rspec ./spec/models/post_spec.rb 
...
Finished in 0.03204 seconds (files took 1.42 seconds to load)
3 examples, 1 failure

Failed examples:

rspec ./spec/models/post_spec.rb:21 #La longueur maximale du sujet du message le rend invalide pour 31 caractères

Je n'ai pas encore ajouté de validation, donc 30 caractères passeront mais 31 caractères seront de la mousse. Ajoutez une validation au modèle.

app/models/post.rb


 class Post < ApplicationRecord
-  validates :subject, presence: true
+  validates :subject, presence: true, length: { maximum: 30 }
 end
$ rspec ./spec/models/post_spec.rb 
...
Finished in 0.02201 seconds (files took 1.4 seconds to load)
3 examples, 0 failures

Vous avez réussi le test. Cela entraînera une erreur à 31 caractères. Essayez-le avec rails c.

Remplacer par FactoryBot

Par exemple, dans le code de test ci-dessus

  post = Post.new(subject: "Ah" * 30, body: "fuga")

Cependant, il est difficile de spécifier le corps à chaque fois. Ce n'est toujours pas grave s'il s'agit de 2 colonnes, mais s'il dépasse 10 colonnes, le code sera inutilement long. À ce moment-là, utilisez factoryBot.

Le factoryBot regarde sous spec / usines /. Cette fois, il n'est pas nécessaire de changer la valeur initiale lors de la création du modèle, mais regardons le contenu.

spec/factories/posts.rb


# frozen_string_literal: true

FactoryBot.define do
  factory :post do
    subject { "MyString" }
    body { "MyText" }
  end
end

Modifiez le fichier post_spec.rb.

spec/models/post_spec.rb


   describe "subject" do
     context "Lorsque vide" do
       it "Devenir invalide" do
-        post = Post.new(subject: "", body: "fuga")
+        post = build(:post, subject: "")
         expect(post).not_to be_valid
       end
     end
     context "par maxlength" do
       context "Pour 30 caractères" do
         it "Devenir valide" do
-          post = Post.new(subject: "Ah" * 30, body: "fuga")
+          post = build(:post, subject: "Ah" * 30)
           expect(post).to be_valid
         end
       end
       context "Pour 31 caractères" do
         it "Devenir invalide" do
-          post = Post.new(subject: "Ah" * 31, body: "fuga")
+          post = build(:post, subject: "Ah" * 31)
           expect(post).not_to be_valid
         end
       end

build est l'équivalent de .new en utilisant factoryBot. Il n'est pas enregistré dans la base de données. Dans ce cas, le sujet est spécifié, mais le corps n'est pas spécifié, donc le corps du factoryBot contiendra «" MyText "».

Exécutez également un test pour chaque modification pour vous assurer qu'elle est correcte.

Remplacer la variable par let

Pour le moment, essayez de le changer comme suit.

spec/models/post_spec.rb


 RSpec.describe Post, type: :model do
   describe "subject" do
     context "Lorsque vide" do
+      let(:post) do
+        build(:post, subject: "")
+      end
       it "Devenir invalide" do
-        post = build(:post, subject: "")
         expect(post).not_to be_valid
       end
     end
     context "par maxlength" do
       context "Pour 30 caractères" do
+        let(:post) do
+          build(:post, subject: "Ah" * 30)
+        end
         it "Devenir valide" do
-          post = build(:post, subject: "Ah" * 30)
           expect(post).to be_valid
         end
       end
       context "Pour 31 caractères" do
+        let(:post) do
+          build(:post, subject: "Ah" * 31)
+        end
         it "Devenir invalide" do
-          post = build(:post, subject: "Ah" * 31)
           expect(post).not_to be_valid
         end
       end

let est une variable limitée à la portée du même bloc de description ou de contexte. Dans Ruby, la dernière expression évaluée est la valeur de retour, donc

  let(:post) do
    build(:post, subject: "Ah" * 31)
  end

Dans le cas de, le post du résultat de l'exécution de la construction devient une variable appelée post par let (: post).

Exercice

Implémentons le test et la validation de la limite obligatoire et de la limite de 100 caractères ou moins sur le corps.

exemple de réponse d'implémentation du corps

spec/models/post_spec.rb


# frozen_string_literal: true

require "rails_helper"

RSpec.describe Post, type: :model do
  describe "subject" do
    context "Lorsque vide" do
      let(:post) do
        build(:post, subject: "")
      end
      it "Devenir invalide" do
        expect(post).not_to be_valid
      end
    end
    context "par maxlength" do
      context "Pour 30 caractères" do
        let(:post) do
          build(:post, subject: "Ah" * 30)
        end
        it "Devenir valide" do
          expect(post).to be_valid
        end
      end
      context "Pour 31 caractères" do
        let(:post) do
          build(:post, subject: "Ah" * 31)
        end
        it "Devenir invalide" do
          expect(post).not_to be_valid
        end
      end
    end
  end

  describe "body" do
    context "Lorsque vide" do
      let(:post) do
        build(:post, body: "")
      end
      it "Devenir invalide" do
        expect(post).not_to be_valid
      end
    end
    context "par maxlength" do
      context "Pour 100 caractères" do
        let(:post) do
          build(:post, body: "Ah" * 100)
        end
        it "Devenir valide" do
          expect(post).to be_valid
        end
      end
      context "Pour 101 caractères" do
        let(:post) do
          build(:post, body: "Ah" * 101)
        end
        it "Devenir invalide" do
          expect(post).not_to be_valid
        end
      end
    end
  end
end

Si vous exécutez rspec à ce stade, ce sera de la mousse

app/models/post.rb


# frozen_string_literal: true

#
#Après la classe
#
class Post < ApplicationRecord
  validates :subject, presence: true, length: { maximum: 30 }
  validates :body, presence: true, length: { maximum: 100 }
end

Réglage d'exclusion car le rubocop est de la mousse. Il vaut mieux ne pas être trop strict car le test peut être contre-productif si vous respectez les normes DRY et de codage.

diff:.rubocop.yml


+ #Longueur de bloc
+ Metrics/BlockLength:
+   Exclude:
+     - "spec/**/*"

À ce stade, si vous exécutez rspec et rubocop, il passera.

A continué

Création d'une API de tableau d'affichage avec certification et autorisation dans le contrôleur Rails 6 # 5, implémentation des routes

[Vers la table de sérialisation]

Recommended Posts

# 4 post-validation et mise en œuvre de test pour créer une API de tableau d'affichage avec certification et autorisation dans Rails 6
Construire une API de tableau d'affichage avec certification et autorisation avec Rails 6 # 18 ・ Implémentation du contrôleur de l'utilisateur final
Créer une API de tableau d'affichage avec autorisation dans Rails 6 # 12 Association d'utilisateur et de publication
Créer une API de tableau d'affichage avec autorisation de certification dans Rails 6 # 11 Test et validation du modèle utilisateur ajoutés
Créez une API de tableau d'affichage avec certification et autorisation avec Rails 6 # 3 RSpec, FactoryBot introduit et post-modèle
Créez une API de tableau d'affichage avec certification et autorisation avec Rails 6 # 1 Construction de l'environnement
Construire une API de tableau d'affichage avec certification et autorisation dans le contrôleur Rails 6 # 5, implémentation des routes
Présentation de # 2 git et rubocop pour créer une API de tableau d'affichage avec autorisation d'authentification dans Rails
Implémentation n ° 8 pour créer une API de tableau d'affichage avec autorisation de certification dans Rails 6
Créer une API de tableau d'affichage avec autorisation de certification dans Rails 6 # 13 Accorder l'en-tête d'authentification
Créez une API de tableau d'affichage avec certification et autorisation dans Rails 6 # 6 show, créez une implémentation
Introduction de # 10 devise_token_auth pour créer une API de tableau d'affichage avec autorisation d'authentification dans Rails 6
Introduction de l'expert n ° 15 pour créer une API de tableau d'affichage avec certification et autorisation dans Rails 6
Créez une API de tableau d'affichage avec certification et autorisation dans Rails 6 # 17 Ajoutez des privilèges d'administrateur
Créer une API de tableau d'affichage avec autorisation de certification dans la mise à jour Rails 6 # 7, détruire l'implémentation
Construire une API de tableau d'affichage avec certification et autorisation dans Rails 6 # 14 Seed Affichage du temps d'exécution
# 16 paramètre de stratégie pour créer une API de tableau d'affichage avec autorisation de certification dans Rails 6
Présentation du sérialiseur n ° 9 pour créer une API de tableau d'affichage avec certification et autorisation dans Rails 6
[Rails] Implémentation de la fonction glisser-déposer (avec effet)
J'ai essayé d'implémenter l'API Rails avec TDD par RSpec. part3-Implémentation d'action avec authentification-
J'ai essayé de créer une fonction de groupe (babillard) avec Rails
J'ai essayé d'implémenter l'API Rails avec TDD par RSpec. part1-Implémentation de l'action sans authentification-
Construction de Rails 6 et environnement PostgreSQL avec Docker
[Rails] Mise en œuvre de la validation qui maintient l'unicité
J'ai essayé d'exprimer le numéro de téléphone (téléphone fixe / téléphone portable) avec une expression régulière dans Rails et d'écrire la validation et le test
Créez un tableau d'affichage simple avec Java + MySQL
[Nuxt / Rails] Implémentation POSTed en utilisant axios et devise_token_auth
Comment créer une API avec GraphQL et Rails