C'est un mémorandum.
Références Rails au quotidien - Introduction aux tests de rails avec RSpec https://leanpub.com/everydayrailsrspec-jp
C'est une méthode pour éliminer la duplication de code et standardiser le traitement (traitement de connexion, etc.). Par exemple, s'il y a cinq tests qui exécutent le processus de connexion à l'avance, lorsque le bouton de connexion est modifié, cinq changements sont nécessaires. Le séparer en un seul module améliore la lisibilité tout en minimisant les modifications.
Essayez de séparer le processus de connexion suivant en modules
#Obtenir l'écran de connexion
visit root_path
#Cliquez sur connexion
click_link "Sign in"
#Saisissez l'adresse e-mail de l'utilisateur dans le champ de texte Email
fill_in "Email", with: user.email
#Entrez le mot de passe comme ci-dessus
fill_in "Password", with: user.password
#Cliquez sur le bouton de connexion
click_button "Log in"
Supposons que le code des méthodes décrites dans ce module soit dispersé dans tout le test.
Pour détacher ce code, créez spec / suprot / login_support.rb et modulez-le.
login_support.rb
module LoginSupport
def sign_in_as(user)
visit root_path
click_link "Sign in"
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
end
#Lire l'ensemble de RSpec
RSpec.configure do |config|
config.include LoginSupport
end
↓
#Si vous voulez le lire explicitement pour chaque test, dans le fichier de spécification que vous voulez lire
include LoginSupport
#Si tel est le cas, il sera lu.
Vous pouvez maintenant appeler les méthodes (méthodes d'assistance) dans le module. Comparons avant et après réécriture. Everyday Rails - Empruntez le code pour vous familiariser avec les tests Rails avec RSpec.
Avant le remplacement
projects_spec.rb
require 'rails_helper'
RSpec.feature "Projects", type: :feature do
scenario "user creates a new project" do
user = FactoryBot.create(:user)
#d'ici
visit root_path
click_link "Sign in"
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
#Remplacez jusqu'à ici par la méthode d'assistance
expect {
click_link "New Project"
fill_in "Name", with: "Test Project"
fill_in "Description", with: "Trying out Capybara"
click_button "Create Project"
expect(page).to have_content "Project was successfully created"
expect(page).to have_content "Test Project"
expect(page).to have_content "Owner: #{user.name}"
}.to change(user.projects, :count).by(1)
end
end
Après remplacement
projects_spec.rb
require 'rails_helper'
RSpec.feature "Projects", type: :feature do
scenario "user creates a new project" do
user = FactoryBot.create(:user)
#d'ici
sign_in_as(user)
#Ou
sign_in_as user
#Mais d'accord
#J'ai remplacé ce qui précède par une méthode d'aide
expect {
click_link "New Project"
fill_in "Name", with: "Test Project"
fill_in "Description", with: "Trying out Capybara"
click_button "Create Project"
expect(page).to have_content "Project was successfully created"
expect(page).to have_content "Test Project"
expect(page).to have_content "Owner: #{user.name}"
}.to change(user.projects, :count).by(1)
end
end
L'important ici est de rendre le nom de la méthode facile à comprendre. Il est important de garder à l'esprit un nom que vous pouvez facilement comprendre, car vous ne pouvez pas comprendre l'opération par le nom de la méthode, et faire référence au fichier d'origine ne fera que rendre le test gênant.
Dans certains cas, les données requises pour le test sont configurées avant le test (processus de création de données tel que la création d'utilisateur) avant d'exécuter la description ou le contexte. Comme before est exécuté à chaque fois que describe ou context est exécuté, les problèmes suivants peuvent survenir. -Parce qu'il est exécuté à chaque fois, cela peut avoir un effet inattendu sur le test. -Il existe un risque élevé que les performances du test soient réduites car il est exécuté à chaque fois. -A mesure que la quantité de test augmente, la quantité de code écrit augmente, ce qui nuit au coût et à la lisibilité.
C'est la lecture retardée par let qui efface cela. Puisque let n'est exécuté que lorsqu'il est appelé, les problèmes ci-dessus peuvent être résolus. Comparons avant et après réécriture. Everyday Rails - Empruntez le code pour vous familiariser avec les tests Rails avec RSpec.
laissez inutilisé
note_spec.rb
require 'rails_helper'
RSpec.describe Note, type: :model do
before do
#Utilisateur créé
@user = User.create(
first_name: "Joe",
last_name: "Tester",
email: "[email protected]",
password: "dottle-nouveau-pavilion-tights-furze",
)
#Création de projet
@project = @user.projects.create(
name: "Test Project",
)
end
it "Doit être valide s'il y a des utilisateurs, des projets, des messages" do
note = Note.new(
message: "This is a sample note.",
user: @user,
project: @project,
)
expect(note).to be_valid
end
it "S'il n'y a pas de message, il est dans un état invalide" do
note = Note.new(message: nil)
note.valid?
expect(note.errors[:message]).to include("can't be blank")
end
describe "Rechercher les messages qui correspondent à la chaîne" do
before do
@note1 = @project.notes.create(
message: "This is the first note.",
user: @user,
)
@note2 = @project.notes.create(
message: "This is the second note.",
user: @user,
)
@note3 = @project.notes.create(
message: "First, preheat the oven.",
user: @user,
)
end
context "Lorsque des données correspondantes sont trouvées" do
it "Renvoyer des notes qui correspondent à la chaîne de recherche" do
expect(Note.search("first")).to include(@note1, @note3)
end
end
context "Lorsqu'aucune donnée correspondante n'est trouvée" do
it "Retourner une collection vide" do
expect(Note.search("message")).to be_empty
end
end
end
end
utiliser let
note_spec.rb
require 'rails_helper'
RSpec.describe Note, type: :model do
#utilisez let au lieu d'avant
let(:user) { FactoryBot.create(:user) }
let(:project) { FactoryBot.create(:project, owner: user) }
it "Doit être valide s'il y a des utilisateurs, des projets, des messages" do
note = Note.new(
message: "This is a sample note.",
user: user,
project: project,
)
expect(note).to be_valid
end
it "S'il n'y a pas de message, il est dans un état invalide" do
note = Note.new(message: nil)
note.valid?
expect(note.errors[:message]).to include("can't be blank")
end
describe "Rechercher les messages qui correspondent à la chaîne" do
#utilisez let au lieu d'avant
let(:note1) {
FactoryBot.create(:note,
project: project,
user: user,
message: "This is the first note."
)
}
let(:note2) {
FactoryBot.create(:note,
project: project,
user: user,
message: "This is the second note."
)
}
let(:note3) {
FactoryBot.create(:note,
project: project,
user: user,
message: "First, preheat the oven."
)
}
context "Lorsque des données correspondantes sont trouvées" do
it "Renvoyer des notes qui correspondent à la chaîne de recherche" do
expect(Note.search("first")).to include(note1, note3)
end
end
context "Lorsqu'aucune donnée correspondante n'est trouvée" do
it "Retourner une collection vide" do
expect(Note.search("message")).to be_empty
end
end
end
end
Lors de l'utilisation précédente, les variables d'instance étaient utilisées pour traverser la portée du test, mais dans let, elles sont décrites par des variables. Maintenant que le test réussit, un problème se pose ici. Ajoutez expect (Note.count) .à l'éq 3 au dernier "retour d'une collection vide".
note_spec.rb
context "Lorsqu'aucune donnée correspondante n'est trouvée" do
it "Retourner une collection vide" do
expect(Note.search("message")).to be_empty
#Ajouter cette phrase
expect(Note.count).to eq 3
end
end
end
end
La description ci-dessus ne passe pas le test. La raison est simple: let est une lecture paresseuse.
En bref, aucune donnée n'est créée à moins d'être appelée.
Avec expect (Note.count) .to eq 3, le test va à la base de données pour trouver les données. Naturellement, le DB est vide car let n'est pas appelé. Cependant, puisque la définition de l'attente est que le nombre de données dans la note est égal à 3, le nombre de données est égal à 0, le test échoue et une erreur se produit.
Une façon de résoudre ce problème est d'appeler simplement let, Un exemple utilisant let! Est présenté ci-dessous.
note_spec.rb
#laisser au lieu de laisser!utilisation
let!(:note1) {
FactoryBot.create(:note,
project: project,
user: user,
message: "This is the first note."
)
}
let!(:note2) {
FactoryBot.create(:note,
project: project,
user: user,
message: "This is the second note."
)
}
let!(:note3) {
FactoryBot.create(:note,
project: project,
user: user,
message: "First, preheat the oven."
)
}
#====réduction=====
context "Lorsqu'aucune donnée correspondante n'est trouvée" do
it "Retourner une collection vide" do
expect(Note.search("message")).to be_empty
#Ajouter cette phrase
expect(Note.count).to eq 3
end
end
end
end
Cela passera le test. Laissez! Précharge pendant que le délai est lu. L'image est la même que précédemment et des données sont créées pour chaque bloc d'évaluation.
Cela signifie que les problèmes mentionnés ci-dessus n'ont pas été résolus. Dans ce cas, utiliser avant ou laisser! Dépend de la situation. Du point de vue de l'apprentissage de moi-même, je pense qu'il est normal d'utiliser avant et de laisser correctement.
En guise de conclusion, laissez essentiellement! Je veux continuer dans le sens de ne pas utiliser. Je voudrais laisser cela à avant lorsque le pré-chargement est nécessaire, plutôt que de faire des erreurs de lecture ou de pocha car il n'y a qu'une différence subtile entre let et let!.
shared_context vous permet d'effectuer la configuration requise avec plusieurs fichiers de test. L'utilisation est similaire au module de support. Comparons avant et après réécriture. Everyday Rails - Empruntez le code pour vous familiariser avec les tests Rails avec RSpec.
tasks_controller.rb
require 'rails_helper'
RSpec.describe TasksController, type: :controller do
#Résumez la configuration ici
let(:user) { FactoryBot.create(:user) }
let(:project) { FactoryBot.create(:project, owner: user) }
let(:task) { project.tasks.create!(name: "Task task") }
describe "#show" do
it "responds with JSON formatted output" do
sign_in user
get :show, format: :json,
params: { project_id: project.id, id: task.id }
expect(response.content_type).to eq "application/json"
end
end
describe "#create" do
it "responds with JSON formatted output" do
new_task = { name: "New test task" }
sign_in user
post :create, format: :json,
params: { project_id: project.id, task: new_task }
expect(response.content_type).to eq "application/json"
end
it "adds a new task to the project" do
new_task = { name: "New test task" }
sign_in user
expect {
post :create, format: :json,
params: { project_id: project.id, task: new_task }
}.to change(project.tasks, :count).by(1)
end
it "requires authentication" do
new_task = { name: "New test task" }
# Don't sign in this time ...
expect {
post :create, format: :json,
params: { project_id: project.id, task: new_task }
}.to_not change(project.tasks, :count)
expect(response).to_not be_success
end
end
end
Créez un fichier séparé et combinez les 3 lignes de let avec shared_context Créer spec / support / contextts / project_setup.rb
project_setup.rb
RSpec.shared_context "project setup" do
let(:user) { FactoryBot.create(:user) }
let(:project) { FactoryBot.create(:project, owner: user) }
let(:task) { project.tasks.create!(name: "Task task") }
end
Revenez à tasks_controller.rb et réécrivez la partie let.
tasks_controller.rb
require 'rails_helper'
RSpec.describe TasksController, type: :controller do
#Supprimer let et projet_setup.Incluez rb.
include_context "project setup"
#====Omis ci-dessous=====
Vous disposez maintenant de plusieurs fichiers de test pour combiner les configurations requises en un seul.
・ Module d'assistance Vous pouvez supprimer les traitements courants tels que les méthodes d'assistance dans un fichier séparé et les inclure si nécessaire. · Laisser Il est possible de créer des données à utiliser pour les tests. Impact sur les tests en raison d'un chargement retardé On peut s'attendre à ce qu'il améliore les performances. ・ Shared_context Il est possible de rassembler la configuration utilisée pour les tests. Découpez-le dans un autre fichier et utilisez-le comme inclusion.
Merci de rester avec nous jusqu'à la fin. Si vous avez des suggestions ou des conseils, je vous serais reconnaissant de bien vouloir commenter.
Recommended Posts