Minitest là gì?
Minitest là một thư viện kiểm thử Ruby, nó cho phép bạn viết test cho mã của bạn theo phong cách TDD.
Đây là framework kiểm thử mặc định cho Rails và cũng là yêu thích của DHH.
Một số người thích nó vì sự đơn giản và lượng mã ít hơn so với đối thủ chính (RSpec).
Như bạn thấy trong hình này:

Bài viết này không phải về việc bạn nên chọn cái nào hoặc cái nào "tốt hơn".
Bài viết này là về cách Minitest hoạt động.
Nếu bạn đang thắc mắc: Chỉ dùng cái nào bạn thích nhất, nhưng bạn vẫn nên quen với cả hai 🙂
Nếu bạn thích học cách mọi thứ hoạt động, bạn sẽ thích bài viết này...
Bất kể thư viện kiểm thử nào là yêu thích của bạn!
Hãy nhìn bên dưới "cái nắp capo"
Một trong những điều mọi người khuyên (kể cả tôi) là đọc mã nguồn vì đó là cách tuyệt vời để học cách mọi thứ hoạt động và cũng là cách tuyệt vời để học một vài thủ thuật Ruby mới mà bạn có thể chưa từng thấy.
Đó là những gì tôi làm với Minitest và tôi sẽ chia sẻ những gì tôi học được.
Hãy bắt đầu với một số mã test thực tế để thảo luận cách nó liên quan đến cách Minitest làm việc.
class Thingy < Minitest::Test
def test_it_works
assert_equal 1, 1
end
end
Vậy Minitest tìm các phương thức test này (như test_it_works) và chạy chúng như thế nào?
Câu trả lời là một chút "phép màu" metaprogramming:
def self.methods_matching(re) public_instance_methods(true).grep(re).map(&:to_s) end
Điều này đến từ lớp Runnable được định nghĩa trong lib/minitest.rb. Mã này tìm tất cả phương thức instance cho lớp hiện tại và chọn những phương thức khớp với biểu thức chính quy.
Vì vậy, nếu bạn gọi methods_matching(/^test_/), bạn sẽ nhận được một mảng với tất cả tên phương thức bắt đầu bằng test_.
Cách Minitest hoạt động
Minitest tìm các phương thức test_ này, sau đó nó gọi chúng.
Điều đó xảy ra trong tệp lib/minitest/test.rb (và cụ thể hơn, trên phương thức runnable_methods, cũng trả về danh sách phương thức theo thứ tự ngẫu nhiên).
Điểm quan trọng:
Điều này hoạt động vì Minitest::Test là lớp con của Runnable.
Mảnh ghép cuối cùng là phương thức lớp run trên Runnable, thực hiện một số lọc bổ sung và sau đó gọi run_one_method với mỗi tên phương thức và một đối tượng reporter.
Đây là mã:
filtered_methods.each do |method_name| run_one_method self, method_name, reporter end
Và điều này cuối cùng gọi phương thức instance run trên Minitest::Test:
capture_exceptions do before_setup; setup; after_setup self.send self.name end
Send là phương thức metaprogramming cho phép bạn gọi phương thức khác trên bất kỳ đối tượng nào dùng chuỗi hoặc symbol.
Block capture_exceptions được dùng để ghi nhận thất bại test và ngoại lệ được ném ra bởi mã của bạn.
def capture_exceptions # :nodoc: yield rescue *PASSTHROUGH_EXCEPTIONS raise rescue Assertion => e self.failures << e rescue Exception => e self.failures << UnexpectedError.new(e) end
Đây là cách tôi thích đọc mã, tập trung vào một khía cạnh hoặc tính năng từ mã bạn đang đọc và sau đó bóc tách lớp một như bóc hành tây.
Nếu bạn không biết ý nghĩa của cái gì đó, như từ khóa yield này, thì hãy tra cứu.
Đó là một phần của quá trình học tập!
Kết luận
Trong bài viết này, bạn đã học cách Minitest dùng metaprogramming để tìm phương thức test của bạn và gọi chúng. Bạn cũng học cách lỗi test và ngoại lệ được thu thập vào mảng để báo cáo.
Bạn có thích loại bài viết "phân tích mã" này không?
Cho tôi biết trong bình luận 🙂
Cũng đừng quên chia sẻ bài này trên mạng xã hội yêu thích và đăng ký newsletter bên dưới nếu bạn chưa phải một phần của 7000+ lập trình viên Ruby như bạn đang tìm cách cải thiện kỹ năng!