การทดสอบเป็นส่วนสำคัญของแอปพลิเคชัน Rails ที่ทำงานได้ดีที่สุด โดยที่การบำรุงรักษาไม่ใช่ฝันร้าย และมีการเพิ่มคุณสมบัติใหม่อย่างสม่ำเสมอ หรือคุณลักษณะที่มีอยู่ได้รับการปรับปรุง น่าเสียดายที่สำหรับหลาย ๆ แอปพลิเคชัน สภาพแวดล้อมการผลิตเป็นที่ที่พวกเขาอยู่ภายใต้ภาระงานหนักหรือการรับส่งข้อมูลที่มีนัยสำคัญเป็นครั้งแรก เป็นเรื่องที่เข้าใจได้เนื่องจากการทดสอบดังกล่าวมีค่าใช้จ่ายสูง
โชคดีที่ Rails มีการสนับสนุนที่ดีไม่เพียงแต่สำหรับการทดสอบยูนิต แบบ end-to-end และการรวมระบบเท่านั้น แต่ยังรวมถึงการทดสอบที่เกี่ยวข้องกับประสิทธิภาพและการโหลดด้วย ฉันจะครอบคลุมเนื้อหาทั้งหมดในบทความและแสดงตัวอย่างเชิงปฏิบัติที่จะช่วยให้คุณเข้าใจวิธีใช้เครื่องมือที่ทดสอบระดับประสิทธิภาพของแอปพลิเคชันอย่างมีประสิทธิภาพ
บทความแบ่งออกเป็นสองส่วน:
-
ทฤษฎี — ฉันจะแสดงให้คุณเห็นว่าเหตุใดการทดสอบจึงมีความจำเป็น ประเภทของการทดสอบที่เราสามารถทำได้ และตัวชี้วัดที่สำคัญเมื่อทำการทดสอบในแอปพลิเคชัน
-
ใช้ได้จริง — เราจะทำให้มือของเราสกปรกและเขียนการทดสอบสำหรับแอปพลิเคชันจริงเพื่อให้ได้ผลลัพธ์
หลังจากอ่านทั้งสองส่วนแล้ว คุณจะมีความเข้าใจอย่างลึกซึ้งยิ่งขึ้นเกี่ยวกับการทดสอบประเภทต่างๆ และวิธีดำเนินการในแอปพลิเคชัน Rails ของคุณ ฟังดูน่าสนใจ? มาเริ่มกันด้วยทฤษฎีเล็กน้อยเกี่ยวกับการทดสอบกัน
การทดสอบในทางทฤษฎี
การทดสอบควรเป็นส่วนหนึ่งของการพัฒนาแอปพลิเคชันทุกประเภทเสมอ หากคุณยังไม่มั่นใจหรือยังไม่ได้เขียนการทดสอบ ต่อไปนี้คือข้อโต้แย้งสำหรับการทดสอบที่จะช่วยคุณ:
- แนะนำการเปลี่ยนแปลงโดยไม่ต้องกังวลว่าจะมีอะไรแตกหัก — นี่คือเหตุผลหลักว่าทำไมการทดสอบจึงมีความจำเป็น ลองนึกภาพการทำงานในแอปขนาดใหญ่ที่คุณต้องคลิกดูทั้งแอปเพื่อให้แน่ใจว่าไม่มีอะไรเสียหายทุกครั้งที่คุณแนะนำการเปลี่ยนแปลง แม้แต่การเปลี่ยนแปลงเล็กน้อย ด้วยการทดสอบ คุณเพียงแค่รันคำสั่งเดียวและกระบวนการตรวจสอบจะเป็นไปโดยอัตโนมัติและรวดเร็ว
- กระบวนการปรับโครงสร้างใหม่อย่างง่าย — ฉันได้กล่าวไว้ข้างต้นว่าการทดสอบมีความสำคัญเมื่อเพิ่มคุณสมบัติใหม่หรือทำการเปลี่ยนแปลง เมื่อทำการทดสอบแล้ว คุณจะรู้สึกสบายใจกับการปรับปรุงโค้ดที่มีอยู่มากขึ้น
- การทดสอบคือรูปแบบของเอกสาร — การทดสอบที่เขียนอย่างดีสามารถเป็นรูปแบบของเอกสารสำหรับชุดคุณลักษณะต่างๆ ในแอปพลิเคชัน พวกเขาไม่เพียงแต่อธิบายว่าคุณลักษณะนี้คืออะไร แต่ยังรวมถึงวิธีการทำงานด้วย
- โอกาสในการคิดทบทวนการใช้งานใหม่ — เมื่อคุณเขียนการทดสอบ คุณมีโอกาสคิดอีกครั้งว่าวิธีที่คุณต้องการใช้โค้ดนั้นถูกต้องและสมเหตุสมผลหรือไม่ นอกจากนี้ คุณเพียงแค่ตรวจสอบว่าโค้ดของคุณทำงานตามที่คุณคาดหวังหรือไม่
ฉันหวังว่าข้อโต้แย้งข้างต้นจะโน้มน้าวให้คุณใช้การทดสอบในระหว่างการพัฒนาแอปใดๆ แม้ว่าการรู้ว่าเหตุใดจึงต้องทดสอบโค้ดจึงเป็นสิ่งสำคัญ แต่การเรียนรู้เกี่ยวกับการทดสอบประเภทต่างๆ ก็มีความสำคัญเช่นกัน
การทดสอบประเภทต่างๆ
มีการทดสอบหลักสามประเภทที่คุณสามารถเขียนเพื่อให้แน่ใจว่าประสิทธิภาพของแอปพลิเคชัน Rails ของคุณถูกต้องและโครงสร้างพื้นฐานทำงานได้ดีภายใต้ภาระงานหนัก ประเภทดังต่อไปนี้:
- โหลดการทดสอบ — การทดสอบประเภทนี้จะตอบคำถามต่อไปนี้:จำนวนผู้ใช้ที่ระบบสามารถจัดการได้พร้อมกันในช่วงเวลาที่กำหนด ลองนึกภาพว่าคุณเปิดตัวผลิตภัณฑ์ที่มีคะแนนสูงสุดในเว็บไซต์ของคุณ และผู้ใช้หลายพันคนต้องการสั่งซื้อพร้อมกัน หากไม่มีการทดสอบการโหลดที่เหมาะสม คุณจะเสี่ยงต่อความผิดพลาดในช่วงเวลาที่สำคัญที่สุด
- การทดสอบความเครียด — ด้วยการทดสอบประเภทนี้ คุณไม่ได้มุ่งเน้นที่การยืนยันจำนวนผู้ใช้ที่ระบบสามารถจัดการได้พร้อมกัน แต่อยู่ที่ว่าระบบจะทำงานอย่างไรเมื่อถึงขีดจำกัดของผู้ใช้
- การทดสอบประสิทธิภาพ — ฉันจะบอกว่าการทดสอบประเภทนี้เป็นผู้ปกครองของการทดสอบความเครียดและโหลด วัตถุประสงค์หลักของการทดสอบดังกล่าวคือเพื่อให้ได้ชุดเมตริกที่เฉพาะเจาะจงซึ่งเราสามารถดำเนินการเพื่อปรับปรุงโค้ดของแอปพลิเคชันได้ ฉันจะพูดถึงเมตริกเหล่านั้นในอีกสักครู่
ดังที่กล่าวไปแล้ว ตอนนี้เราพร้อมที่จะย้ายไปยังขั้นตอนสุดท้ายของส่วนทฤษฎี:เรียนรู้ว่าตัวชี้วัดใดมีความสำคัญเมื่อทำการทดสอบประสิทธิภาพในแอปพลิเคชัน Rails หากไม่มีความรู้นั้น เราจะไม่ตีความผลการทดสอบอย่างถูกต้องและตัดสินใจว่าควรเปลี่ยนรหัสหรือไม่
ตัวชี้วัดที่สำคัญ
ประเภทของเมตริกที่คุณได้รับอาจแตกต่างกันไปตามเครื่องมือที่คุณใช้ในการทดสอบ แต่โดยทั่วไป เราสามารถจัดกลุ่มเมตริกเหล่านี้ให้เป็นชุดเมตริกที่ค่อนข้างธรรมดาได้:
- เวลาตอบสนอง — เวลาระหว่างการร้องขอและการตอบกลับที่แสดงในเบราว์เซอร์ ตัวชี้วัดนี้แสดงให้เราเห็นว่าผู้ใช้ต้องรอนานแค่ไหนก่อนที่จะได้รับข้อมูลที่เขาขอ บางครั้งเรียกว่าเวลาดำเนินการ
- การใช้หน่วยความจำ — จำนวนหน่วยความจำที่ใช้สำหรับคำขอที่กำหนด นี่เป็นข้อมูลสำคัญส่วนหนึ่งเนื่องจากจะชี้ให้คุณทราบถึงจุดที่คุณสามารถปรับปรุงโค้ดได้ เพื่อให้ระบบตอบสนองได้เร็วขึ้นและใช้ทรัพยากรน้อยลง
- การจัดสรรวัตถุ — การจัดสรรหน่วยความจำสูงทำให้เกิดการใช้หน่วยความจำสูงและเวลาตอบสนองนาน เมตริกนี้จะนำคุณไปยังตำแหน่งที่แน่นอนในโค้ดซึ่งมีการจัดสรรออบเจ็กต์จำนวนมาก คุณจึงตรวจสอบได้ทันที
คุณสามารถมีตัววัดได้มากขึ้นเมื่อทำการทดสอบ แต่สามสิ่งนี้สำคัญที่สุดและจะใช้ได้กับแอปพลิเคชันใดๆ ที่คุณทดสอบ ตอนนี้เราเริ่มสกปรกและเขียนบททดสอบจริงได้แล้ว
แบบฝึกหัด
เราไม่สามารถเขียนการทดสอบโดยไม่ต้องทดสอบอะไรได้เลย นั่นเป็นเหตุผลที่ขั้นตอนแรกในส่วนการฝึกหัดคือการเขียนแอปพลิเคชัน Rails แบบง่ายๆ ที่เราสามารถเขียนแบบทดสอบได้
ตัวอย่างการใช้งานรางรถไฟ
ฉันจะใช้ Ruby 3.0.1 และ Rails 6.1.3.1 แต่คุณสามารถใช้เวอร์ชันใดก็ได้ที่คุณพอใจ หากคุณติดตั้ง Ruby และ Rails ไว้ ขั้นตอนต่อไปคือการสร้างโครงร่างของแอปพลิเคชัน:
rails new simpleapp -d=postgresql
สำหรับจุดประสงค์ของบทความ ฉันจะสร้างแอปที่แสดงรายชื่อผู้ใช้พร้อมกับชื่อสัตว์เลี้ยงของพวกเขา โครงสร้างดังกล่าวจะช่วยให้เราสร้างข้อความค้นหา N+1 ได้อย่างง่ายดาย ซึ่งจะให้ความสนุกสนานมากขึ้นเมื่อทำการทดสอบประสิทธิภาพ และตรวจสอบผลกระทบต่อความเร็วและเมตริกอื่นๆ ที่การเปลี่ยนแปลงจะเกิดขึ้น
ก่อนที่เราจะสร้างโมเดล เรามาสร้างฐานข้อมูลกันก่อน:
cd simpleapp/
bin/rails db:create
ตอนนี้ เราสามารถสร้างแบบจำลองได้:
rails g model User name:string
rails g model Animal name:string user:references
bin/rails db:migrate
การอัปเดตเพียงเล็กน้อยสำหรับ User
โมเดลที่สะท้อนความสัมพันธ์กับ Animal
รุ่น:
class User < ApplicationRecord
has_many :animals
end
ตอนนี้เราเพิ่มเมล็ดใน db/seeds.rb
. ได้แล้ว ไฟล์:
people = {
'Tim' => ['Pinky', 'Rick'],
'Martha' => ['Rudolph'],
'Mark' => ['Niki', 'Miki', 'Bella'],
'Tina' => ['Tom', 'Luna']
}
people.each_pair do |name, pets|
user = User.create(name: name)
pets.each do |pet_name|
user.animals.create(name: pet_name)
end
end
และโหลดข้อมูลลงฐานข้อมูล:
bin/rails db:seed
ฉันจะสร้างตัวควบคุมหนึ่งตัวพร้อมการมอบหมายของผู้ใช้ จากนั้นในมุมมอง ฉันจะแสดงรายการผู้ใช้ทั้งหมดที่มีชื่อสัตว์เลี้ยงของพวกเขา ฉันตั้งใจใช้โค้ดที่ทำให้เกิดปัญหาด้านประสิทธิภาพเพื่อให้คุณวัดผลการปรับปรุงได้ในภายหลัง
touch app/controllers/home_controller.rb
mkdir app/views/home
touch app/views/home/index.html.erb
ตัวควบคุมนั้นเรียบง่าย:
class HomeController < ApplicationController
def index
@users = User.all
end
end
และมุมมองด้วย:
<h1>List</h1>
<ul>
<% @users.each do |user| %>
<li><%= user.name %> (<%= user.animals.count %>)
<ul>
<% user.animals.each do |animal| %>
<li><%= animal.name %></li>
<% end %>
</ul>
</li>
<% end %>
</ul>
ขั้นตอนสุดท้ายคือการอัพเดต config/routes.rb
เพื่อให้ Rails รู้ว่าเราต้องการเห็นอะไรเมื่อไปที่ URL หลัก:
Rails.application.routes.draw do
root to: 'home#index'
end
โหลดการทดสอบด้วย JMeter
JMeter เป็นซอฟต์แวร์โอเพ่นซอร์สที่สร้างโดยมูลนิธิซอฟต์แวร์ Apache ซึ่งออกแบบมาเพื่อโหลดลักษณะการทำงานของการทดสอบ เนื่องจากเป็นโปรแกรมที่สร้างด้วย Java คุณจึงติดตั้งบนระบบปฏิบัติการใดก็ได้ คุณสามารถดาวน์โหลดไฟล์ได้ที่นี่:https://jmeter.apache.org/download_jmeter.cgi
หากคุณกำลังทำงานบนระบบ macOS คุณสามารถติดตั้ง JMeter ด้วย Homebrew ได้อย่างง่ายดาย:
brew install jmeter
หลังการติดตั้ง คุณสามารถรันโปรแกรมด้วยคำสั่งต่อไปนี้:
jmeter
การกำหนดค่าการทดสอบ
ขั้นตอนการกำหนดค่าประกอบด้วยขั้นตอนต่อไปนี้:
- การเพิ่มกลุ่มเธรด — ระบุจำนวนผู้ใช้และระยะเวลาที่แต่ละคนจะเข้าชมเว็บไซต์ของคุณ
- การกำหนดค่าคำขอ HTTP — ระบุปลายทางที่ JMeter ควรโดน
- การตั้งค่าเมตริกที่เราสนใจ
มาดูการกำหนดค่าการทดสอบอย่างง่ายทีละขั้นตอนเพื่อจำลองคำขอของผู้ใช้รายเดียวไปยังหน้าหลักของแอปอย่างง่ายที่เราสร้างขึ้นก่อนหน้านี้
เพิ่มกลุ่มกระทู้
เลือก Add -> Threads (Users) -> Thread Group จากเมนูที่ขยายออกหลังจากที่คุณคลิกขวาที่ “Test Plan”:
ระบุจำนวนผู้ใช้และคุณสมบัติเพิ่มเติม:
กำหนดค่าคำขอ HTTP
คลิกขวาที่เธรดที่เราสร้างในขั้นตอนก่อนหน้าแล้วเลือก Add -> Sampler -> HTTP Request:
กำหนดค่าโปรโตคอล ชื่อเซิร์ฟเวอร์ พอร์ต และเส้นทางของคำขอ:
ระบุมุมมองผลลัพธ์
คลิกขวาที่คำขอ HTTP และเลือก เพิ่ม -> Listener -> ดูแผนผังผลลัพธ์:
ดำเนินการทดสอบ
การทดสอบได้รับการกำหนดค่าแล้ว และเราสามารถเรียกใช้งานได้ ในการดำเนินการนี้ เพียงคลิกที่ปุ่มเล่นสีเขียว:
อย่างที่คุณเห็น แอปพลิเคชันผ่านการทดสอบ แต่เป็นเพียงคำขอเดียว ผลลัพธ์จึงชัดเจน คุณสามารถทดลองกับจำนวนผู้ใช้และตัวเลือกการกำหนดค่าอื่นๆ เพื่อดูว่าแอปพลิเคชันทำงานอย่างไร จากการทดสอบของฉัน แอปธรรมดาเริ่มหยุดทำงานเมื่อมีผู้ใช้ประมาณ 200 คนเริ่มเข้าถึงพร้อมกัน
ขั้นตอนต่อไป
หลังจากทำการทดสอบโหลด คุณจะทราบจุดบกพร่องของแอปพลิเคชันของคุณ เมื่อเข้าใจขีดจำกัดของผู้ใช้แล้ว ตอนนี้คุณสามารถทำการทดสอบความเครียดเพื่อดูว่าแอปพลิเคชันทำงานอย่างไร
การทดสอบประสิทธิภาพกับ Ruby-prof
คุณลักษณะการทดสอบประสิทธิภาพมีอยู่ใน Rails จนถึงเวอร์ชัน 3 จากนั้นจึงแยกไปยัง gem ที่แยกต่างหาก https://github.com/rails/rails-perftest เนื่องจากฉันมีปัญหาในการใช้งานกับ Rails เวอร์ชันล่าสุด ฉันจึงตัดสินใจไม่รวมไว้ในบทความนี้ แต่ฉันจะใช้ไลบรารี่ ruby-prof ที่ทำงานได้ดีแทน
ตามปกติ ขั้นตอนแรกคือการเพิ่มอัญมณีลงในแอปพลิเคชันของเรา:
bundle add ruby-prof
ขั้นตอนที่สองและขั้นตอนสุดท้ายของกระบวนการกำหนดค่าคือการอัพเดต config/application.rb
และใช้มิดเดิลแวร์สำหรับอัญมณี เพื่อให้ห้องสมุดสามารถตรวจสอบคำขอของเราโดยอัตโนมัติและสร้างรายงานโดยอิงจากคำขอเหล่านั้น:
module Simpleapp
class Application < Rails::Application
config.middleware.use Rack::RubyProf, :path => './tmp/profile'
end
end
ขณะนี้คุณสามารถเข้าถึงแอปได้แล้ว และทุกครั้งที่คุณดำเนินการตามคำขอ เจมจะสร้างรายงานใหม่ ดูเหมือนว่านี้:
คุณสามารถค้นหาได้ภายใต้เส้นทางที่กำหนดค่าไว้ ซึ่งก็คือ tmp/profile
ในกรณีของเรา รายงานที่สองก็ถูกสร้างขึ้นเช่นกัน และจะแสดง call stack ซึ่งเป็นตัวชี้วัดที่ค่อนข้างมีประโยชน์เมื่อทำการดีบักปัญหาด้านประสิทธิภาพในแอปพลิเคชัน Rails
สิ่งสำคัญคือต้องจำไว้ว่าการตั้งค่า cache_classes
และ cache_template_loading
ตั้งค่าเป็น true
จะทำให้แอปพลิเคชันช้าลงและครอบงำเมตริกแอปพลิเคชันเนื่องจาก Rails จะพยายามโหลดไฟล์ที่จำเป็น
สรุป
การทดสอบเป็นส่วนสำคัญของทุกกระบวนการพัฒนา การตรวจสอบว่าโค้ดทำงานตามที่เราต้องการหรือไม่นั้นสำคัญพอๆ กับการตรวจสอบว่าโซลูชันของเรามีประสิทธิภาพที่ดีหรือไม่ การข้ามการทดสอบนำไปสู่ปัญหาร้ายแรงที่ส่งผลต่อประสิทธิภาพของแอปและความไว้วางใจของผู้ใช้ หวังว่าการทดสอบจะไม่ยากขนาดนั้น
ในบทความนี้ เราได้กล่าวถึงประเด็นสำคัญของการทดสอบดังต่อไปนี้:
- เหตุผลที่คุณควรทดสอบโค้ดของคุณ
- การทดสอบประสิทธิภาพประเภทต่างๆ
- วิธีทดสอบประสิทธิภาพของแอป Rails
ฉันหวังว่าตอนนี้คุณจะมั่นใจมากขึ้นว่าทำไมการเขียนแบบทดสอบจึงสำคัญ เพราะคุณรู้ว่าทำไมและอย่างไร
หากคุณสนใจที่จะตรวจสอบประสิทธิภาพของแอปไม่เพียงแต่ในเครื่องเท่านั้น แต่ยังรวมถึงในสภาพแวดล้อมการใช้งานจริงหรือการแสดงละครด้วย คุณควรตรวจสอบ AppSignal ด้วย
ป.ล. หากคุณต้องการอ่านโพสต์ Ruby Magic ทันทีที่ออกจากสื่อ สมัครรับจดหมายข่าว Ruby Magic ของเราและไม่พลาดแม้แต่โพสต์เดียว!