Au lieu du minitest Rails standard, nous introduirons RSpec, qui a un taux d'adoption plus élevé que le minitest en pratique. Nous en apprendrons plus sur ** TDD (Test Driven Development) et BDD (Behavior Driven Development) **, qui sont des méthodes de test.
Capybara ・ ・ ・ Simule le fonctionnement du navigateur d'applications Web FactoryBot ・ ・ ・ Un joyau qui prend en charge la création d'une base de données de test
group :development, :test do
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'rspec-rails', '~> 4.0.0'
gem 'factory_bot_rails', '~> 4.11'
gem 'capybara', '~> 2.13'
end
$bundle
$bin/rails g rspec:install
Supprimer le répertoire minitest
$rm -r ./test
Écrivez la description suivante en .rspec afin que le résultat de l'exécution du test soit facilement visible.
--format documentation
coloration
--color
spec/spec_helper.rb
require 'capybara/rspec'
RSpec.configure do |config|
config.before(:each, type: :system) do
driven_by :selenium_chrome_headless
end
Installez des pilotes Web qui installeront facilement le pilote Chrome
Ajout de gem'webdrivers'
$ mkdir spec/support
$ touch spec/support/driver_setting.rb
spec/support/driver_setting.rb
RSpec.configure do |config|
config.before(:each, type: :system) do
#Lors de l'exécution de Spec, le navigateur peut démarrer automatiquement et vérifier le comportement.
# driven_by(:selenium_chrome)
#Browser OFF lorsque Spec est exécuté
driven_by(:selenium_chrome_headless)
end
end
Normalement, vous ne pouvez pas appeler une méthode sans FactoryBot user = FactoryBot.create(:user)
En ajoutant les paramètres ci-dessus, la description de FactoryBot peut être omise. user = create(:user)
spec/rails_helper.rb
require "support/factory_bot"
spec/support/factory_bot.rb
RSpec.configure do |config|
#Simplification des appels FactoryBot
config.include FactoryBot::Syntax::Methods
#Empêcher l'usine de charger correctement en raison du ressort
config.before :all do
FactoryBot.reload
end
end
spec/rails_helper.rb
#Décommentez ce code
# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
** Définir l'usine utilisateur **
spec/factories/users.rb
FactoryBot.define do
factory :user do
name { 'Utilisateur test' }
email { '[email protected]' }
password { 'password' }
end
end
** Définir une usine d'avis **
spec/factories/reviews.rb
FactoryBot.define do
factory :review do
title { "MyString" }
author { "MyString" }
description { "MyText" }
user
end
end
Ce joyau accélère le démarrage du test
group :development do
gem 'spring-commands-rspec'
end
bundle install
puis bundle exec spring binstub rspec
généreront un fichier rspec dans le répertoire bin
#!/usr/bin/env ruby
begin
load File.expand_path('../spring', __FILE__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
require 'bundler/setup'
load Gem.bin_path('rspec-core', 'rspec')
Shoulda Mathers est un joyau qui permet d'écrire des tests de manière concise et intuitive en ajoutant une syntaxe de test à une ligne à RSpec et Minitest.
group :test do
gem 'shoulda-matchers'
#Pour rails5 ou version ultérieure
gem 'shoulda-matchers', git: 'https://github.com/thoughtbot/shoulda-matchers.git', branch: 'rails-5'
end
spec/support/shoulda_matchers.rb
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
spec/rails_helper.rb
require "support/shoulda_matchers"
config/application.rb
require_relative 'boot'
require 'rails/all'
require 'uri'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module BookReviewApp
class Application < Rails::Application
config.load_defaults 5.1
config.generators.template_engine = :slim
config.i18n.default_locale = :ja
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
config.generators do |g|
g.test_framework :rspec,
fixtures: false,
view_specs: false,
helper_specs: false,
routing_specs: false
end
end
end
Créez un dossier appelé models dans le dossier spec, créez un fichier user_spec.rb dans le dossier models et écrivez le code suivant
$ mkdir spec/models
$ touch spec/models/user_spec.rb
spec/mogels/user_spec.rb
require 'rails_helper'
RSpec.describe User, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
context "if name is entered" do
it 'if user registration is successful' do
end
end
context "if name is not entered" do
it 'if user registration fails' do
end
end
context 'if email is entered' do
it 'if user registration is successful' do
end
end
context 'if email is not entered' do
it 'if user registration fails' do
end
end
context "if password is entered" do
it 'if user registration is successful' do
end
end
context "if password is not entered" do
it 'if user registration fails' do
end
end
end
#La langue de la description du test dépend de la syntaxe
#exemple de syntaxe
example 'Japonais' do
#Ecrire le code
end
#syntaxe
it 'English' do
#Ecrire le code
end
Si vous souhaitez tester uniquement ce fichier, vous devez spécifier le fichier
$ bundle exec rspec spec/models/user_spec.rb
exemples: tests existants / échecs: tests ayant échoué / en attente: tests non exécutés
$ mkdir spec/system/
$ touch spec/system/reviews_spec.rb
spec/system/reviews_spec.rb
require 'rails_helper'
describe 'Fonction de gestion des revues', type: :system do
describe 'Fonction d'affichage de liste' do
before do
#Créer l'utilisateur A
#Créer un avis dont l'auteur est l'utilisateur A
end
context 'Lorsque l'utilisateur est connecté' do
before do
#L'utilisateur A se connecte
end
it 'Les avis créés par l'utilisateur A sont affichés' do
#Confirmez que le titre de l'avis créé est affiché à l'écran
end
end
end
end
Dans describe
, décrivez" ce que vous essayez de décrire la spécification pour "(cible du test).
La description la plus externe décrit le sujet de l'ensemble du fichier Spec.
Décrivez un thème plus détaillé dans la description plus approfondie.
context
est utilisé pour classer le contenu du test en fonction de la variation de" statut / état ".
Vous pouvez organiser et faciliter les tests pour voir que vous devez tester pour voir s'ils fonctionnent correctement dans diverses conditions.
before
est l'endroit où écrire le code pour exécuter les" conditions préalables "de la zone entière.
Si vous écrivez avant dans describe ou context, le code écrit dans le bloc before sera exécuté avant d'exécuter le code de test dans la zone de description ou de contexte correspondante.
it
décrit le comportement attendu dans les phrases et le code dans le bloc. Si la cible fonctionne comme prévu, le test réussit.
spec/system/reviews_spec.rb
require 'rails_helper'
describe 'Fonction de gestion des revues', type: :system do
describe 'Fonction d'affichage de liste' do
before do
#Créer l'utilisateur A
user_a = create(:user, name: 'Utilisateur A', email: '[email protected]')
#Créer un avis dont l'auteur est l'utilisateur A
create(:review, name: 'Premier examen', user: user_a)
end
context 'Lorsque l'utilisateur est connecté' do
before do
#L'utilisateur A se connecte
visit login_path
fill_in 'adresse mail', with: '[email protected]'
fill_in 'mot de passe', with: 'password'
click_button 's'identifier'
end
it 'Les avis créés par l'utilisateur A sont affichés' do
#Confirmez que le titre de l'avis créé est affiché à l'écran
expect(page).to have_content 'Premier examen'
end
end
end
end
#Si le test échoue
$ bundle exec rspec spec/system/reviews_spec.rb
Fonction de gestion des revues
Fonction d'affichage de liste
Lorsque l'utilisateur est connecté
Les avis créés par l'utilisateur A sont affichés(FAILED - 1)
Failures:
1)Fonction de gestion des avis Fonction d'affichage de liste Les avis créés par l'utilisateur A s'affichent lorsque l'utilisateur est connecté.
Failure/Error: user_a = FactoryBot.create(user, name: 'Utilisateur A', email: '[email protected]')
NameError:
undefined local variable or method `user' for #<RSpec::ExampleGroups::Nested::Nested::Nested:0x00007fed26346f28>
[Screenshot]: tmp/screenshots/failures_r_spec_example_groups_nested_nested_nested_Les avis créés par l'utilisateur a sont affichés_412.png
# ./spec/system/reviews_spec.rb:7:in `block (3 levels) in <top (required)>'
Finished in 4.19 seconds (files took 5.32 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/system/reviews_spec.rb:21 #Fonction de gestion des avis Fonction d'affichage de liste Les avis créés par l'utilisateur A s'affichent lorsque l'utilisateur est connecté.
spec/system/reviews_spec.rb
.
.
.
describe 'Nouvelle fonction d'examen' do
let(:login_user) { :user_a }
before do
visit new_review_path
fill_in 'Titre', with: review_name
click_button 'Publier'
end
context 'Lors de la saisie d'un titre sur l'écran du nouvel article' do
let(:review_name) { 'Rédiger un test pour un nouveau message' }
it 'Publié avec succès' do
expect(page).to have_selector 'alert-success', text: 'Rédiger un test pour un nouveau message'
end
end
context 'Lorsque vous n'avez pas saisi le titre sur l'écran du nouvel article' do
let(:review_name) { '' }
it 'Obtenez une erreur' do
within '#error_explanation' do
expect(page).to have_content 'Veuillez entrer un titre'
end
end
end
end
end
let est une fonction qui peut être utilisée dans une image similaire à "attribuer une valeur à une variable de portée de test avant le traitement" (elle ne crée pas réellement de variable)
let (nom de la définition) {contenu de la définition}
Un matcher appelé have_selector vous permet de spécifier un élément spécifique en HTML avec un sélecteur (sélecteur CSS).
have_selector
En utilisant la méthode appelée within, vous pouvez restreindre la plage de recherche à une plage spécifique à l'écran en inspectant le contenu de la page à l'intérieur du bloc within.
within'spécifiez une plage 'do
Faites un aperçu avec des commentaires
spec/models/user_spec.rb
# validations
describe "validations" do
#Existence
describe "presence" do
#Nom, adresse e-mail
it "name and email should not ro be empty/falsy"
#Mot de passe, confirmation du mot de passe
context "when password and confirmation is not present" do
it "@user is invalid"
end
end
#Nombre de caractères caractères
describe "charesters" do
#Nom: jusqu'à 20 caractères
context "when name is too long"
it "@user is inavlid"
#Mot de passe, confirmation du mot de passe: 6 caractères minimum
describe "when password is too short"
it "@user is inavlid"
end
#Format Email
describe "email format" do
#format invalide
context "when invalid format" do
it "@user is inavlid"
#format valide
context "when valid format" do
it "@user is valid"
end
end
end
end
Remplissez les commentaires
spec/models/user_spec.rb
RSpec.describe User, type: :model do
#Modèle en attente
pending "add some examples to (or delete) #{__FILE__}"
# validations
describe "validations" do
#Existence
describe "presence" do
#Nom, adresse e-mail
it { should validate_presence_of :name }
it { should validate_presence_of :email }
#Mot de passe, confirmation du mot de passe
context "when password and confirmation is not present" do
before { user.password = user.password_confirmation = " " }
it { should_not be_valid }
end
end
#Nombre de caractères caractères
describe "charesters" do
#Nom: jusqu'à 20 caractères,Mot de passe: 6 caractères minimum
it { should validate_length_of(:name).is_at_most(20) }
it { should validate_length_of(:password).is_at_least(6) }
end
#Format Email
describe "email format" do
#format invalide
context "when invalid format" do
#Objet invalide
it "should be invalid" do
invalid_addr = %w[user@foo,com user_at_foo.org example.user@foo. foo@bar_baz.com foo@bar+baz.com]
invalid_addr.each do |addr|
user.email = addr
expect(user).not_to be_valid
end
end
end
end
#format valide
context "when valid format" do
#Objets valides
it "should be valid" do
valid_addr = %w[[email protected] [email protected] [email protected] [email protected]]
valid_addr.each do |addr|
user.email = addr
expect(user).to be_valid
end
end
end
end
end
↓ Résultat du test ↓
console.log
$ bundle exec rspec spec/models/user_spec.rb
User
add some examples to (or delete) /Users/kiyokawakouji/Rails-app/book_review_app/spec/models/user_spec.rb (PENDING: Not yet implemented)
validations
presence
is expected to validate that :name cannot be empty/falsy
is expected to validate that :email cannot be empty/falsy
when password and confirmation is not present
example at ./spec/models/user_spec.rb:17 (FAILED - 1)
charesters
is expected to validate that the length of :name is at most 20
is expected to validate that the length of :password is at least 6
email format
when invalid format
should be invalid (FAILED - 2)
when valid format
should be valid (FAILED - 3)
Pending: (Failures listed here are expected and do not affect your suite's status)
1) User add some examples to (or delete) /Users/kiyokawakouji/Rails-app/book_review_app/spec/models/user_spec.rb
# Not yet implemented
# ./spec/models/user_spec.rb:5
Failures:
1) User validations presence when password and confirmation is not present
Failure/Error: before { user.password = user.password_confirmation = " " }
NameError:
undefined local variable or method `user' for #<RSpec::ExampleGroups::User::Validations::Presence::WhenPasswordAndConfirmationIsNotPresent:0x00007fd1586e2770>
# ./spec/models/user_spec.rb:16:in `block (5 levels) in <top (required)>'
2) User validations email format when invalid format should be invalid
Failure/Error: user.email = addr
NameError:
undefined local variable or method `user' for #<RSpec::ExampleGroups::User::Validations::EmailFormat::WhenInvalidFormat:0x00007fd15831d6f8>
# ./spec/models/user_spec.rb:34:in `block (6 levels) in <top (required)>'
# ./spec/models/user_spec.rb:33:in `each'
# ./spec/models/user_spec.rb:33:in `block (5 levels) in <top (required)>'
3) User validations when valid format should be valid
Failure/Error: user.email = addr
NameError:
undefined local variable or method `user' for #<RSpec::ExampleGroups::User::Validations::WhenValidFormat:0x00007fd1582d5790>
# ./spec/models/user_spec.rb:46:in `block (5 levels) in <top (required)>'
# ./spec/models/user_spec.rb:45:in `each'
# ./spec/models/user_spec.rb:45:in `block (4 levels) in <top (required)>'
Finished in 0.61427 seconds (files took 5.94 seconds to load)
8 examples, 3 failures, 1 pending
Failed examples:
rspec ./spec/models/user_spec.rb:17 # User validations presence when password and confirmation is not present
rspec ./spec/models/user_spec.rb:31 # User validations email format when invalid format should be invalid
rspec ./spec/models/user_spec.rb:43 # User validations when valid format should be valid
** Explication des résultats des tests ci-dessous **
Comme écrit dans le commentaire, panding
est un modèle qui montre comment écrire RSpec (cette fois je l'ai réveillé sans l'effacer), donc c'est fini.
(FAILED-number)
indique que le code de test a échoué. Cette fois, le code de test à trois endroits a échoué.
Failures: ~
affiche le code correspondant et les détails d'erreur indiquant que le test a échoué.
Exemple d'échecs: ~
affiche la ligne du code correspondant dans le fichier où le test a échoué et le comportement attendu.
Puisqu'il s'agit d'un test de modèle, nous vérifierons les validations
app/models/user.rb
class User < ApplicationRecord
devise :database_authenticatable, :rememberable,
:validatable, :timeoutable, :registerable, :confirmable
#La valeur du nom est-elle vide?
validates :name, presence: true
#La valeur du nom est-elle de 20 caractères ou moins?
validates :name, length: { maximum: 20 }
#Réduisez l'adresse e-mail lors de l'enregistrement de l'adresse e-mail dans la base de données
before_save { self.email = email.downcase }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
#L'e-mail correspond-il à l'entrée de confirmation?
validates :email, { presence: true, format: { with: VALID_EMAIL_REGEX } }
validates :email, :encrypted_password, confirmation: true
#La valeur du mot de passe est-elle vide?
validates :password, presence: true
#La valeur du mot de passe est-elle de 6 caractères ou plus?
validates :password, length: { minimum: 6 }
#Lier l'utilisateur et l'examen sur la base de données
has_many :reviews, dependent: :destroy, foreign_key: :review_user_id
end
** Paramètre pour réexécuter uniquement les tests ayant échoué (option --only-failures) **
spec_helper.rb
RSpec.configure do |config|
config.example_status_persistence_file_path = "./spec/examples.txt"
end
------------------------------------------------------------------
Si vous utilisez git.Ajoutez également les paramètres suivants à gitignore.
spec/examples.txt
$ bundle exec rspec --only-failures
Liste des options pour rspec
$ rspec --help
Sortie sans exécuter une liste de tests
$ rspec --dry-run
Avertissement de test de sortie
$ rspec --warnings
Cette commande affiche un avertissement dans le fichier de spécifications. S'il y a une faute d'orthographe, mettez-la dans l'avertissement et affichez-la
Quand j'ai essayé $ rsoec --warnings
, la sortie suivante était sortie
WARN: Unresolved or ambiguous specs during Gem::Specification.reset:
diff-lcs (>= 1.2.0, < 2.0)
Available/installed versions of this gem:
- 1.4
- 1.3
WARN: Clearing out unresolved specs. Try 'gem cleanup <gem>'
Please report a bug if this causes problems.
~~réduction~~
On dit que la même gemme est installée dans plusieurs versions et il n'est pas possible de décider laquelle gérer sur le système. Vous devez supprimer l'ancienne version de la gemme et la réduire à une seule ou choisir une version spécifique.
** Test global ** ・ Spécifications du système / Spécifications des fonctionnalités ・ Test d'intégration (demande de spécification) ・ Test fonctionnel (spécification du contrôleur) ** Test de pièces individuelles ** ・ Modèle (spécification du modèle) ・ Spécifications de routage · Voir les spécifications ・ Helper Spec ・ Mailer (Mailer Spec) ・ Travail (spécification du travail)
Vous devez vous assurer que le code de test fonctionne comme prévu. Ceci est également connu sous le nom d '«exercice du code sous test».
Pour prouver qu'il ne s'agit pas d'un faux positif, par exemple, changez to
en to_not
et inversez l'attente.
spec/models/user_spec.rb
#S'il n'y a pas de nom, il est dans un état invalide(Succès)
it "is invalid without a first name" do
user = User.new(first_name: nil)
user.valid?
expect(user.errors[:first_name]).to include("can't be blank")
end
#S'il n'y a pas de nom, il est dans un état invalide(Échec)
it "is invalid without a first name" do
user = User.new(first_name: nil)
user.valid?
expect(user.errors[:first_name]).to_not include("can't be blank")
end
Rails RSpec Preparation and Test Code Basics [Rails] Introduction et configuration initiale de "RSpec + FactoryBot + Capybara + Webdrivers" pour tester l'écriture Création d'un environnement SystemSpec avec Rails + Selenium + Docker https://github.com/everydayrails/everydayrails-rspec-2017 Introduction à RSpec utilisable, Partie 1 «Comprendre la syntaxe de base et les fonctions utiles de RSpec» Paramètres RSpec Options utiles pour Rspec Comment utiliser les rappels Rails que j'ai finalement compris après avoir souffert
Recommended Posts