Tóm tắt: Chủ đề của RSpec là một biến đặc biệt đề cập đến đối tượng đang được kiểm tra. Kỳ vọng có thể được thiết lập ngầm trên đó, hỗ trợ các ví dụ một dòng. Nó rõ ràng đối với người đọc trong một số trường hợp thành ngữ, nhưng khó hiểu và nên tránh. Các let
biến của RSpec chỉ là các biến được khởi tạo (ghi nhớ) một cách lười biếng. Chúng không khó để làm theo chủ đề, nhưng vẫn có thể dẫn đến các bài kiểm tra rối vì vậy nên được sử dụng một cách thận trọng.
Chủ đề
Làm thế nào nó hoạt động
Chủ thể là đối tượng đang được kiểm tra. RSpec có một ý tưởng rõ ràng về chủ đề. Nó có thể được xác định hoặc không. Nếu đúng như vậy, RSpec có thể gọi các phương thức trên đó mà không cần tham chiếu đến nó một cách rõ ràng.
Theo mặc định, nếu đối số đầu tiên cho một nhóm ( describe
hoặc context
khối) mẫu ngoài cùng là một lớp, RSpec sẽ tạo một thể hiện của lớp đó và gán nó cho chủ thể. Ví dụ: các thông số sau:
class A
end
describe A do
it "is instantiated by RSpec" do
expect(subject).to be_an(A)
end
end
Bạn có thể tự xác định chủ đề bằng subject
:
describe "anonymous subject" do
subject { A.new }
it "has been instantiated" do
expect(subject).to be_an(A)
end
end
Bạn có thể đặt tên cho chủ thể khi bạn xác định nó:
describe "named subject" do
subject(:a) { A.new }
it "has been instantiated" do
expect(a).to be_an(A)
end
end
Ngay cả khi bạn đặt tên chủ đề, bạn vẫn có thể đề cập đến nó một cách ẩn danh:
describe "named subject" do
subject(:a) { A.new }
it "has been instantiated" do
expect(subject).to be_an(A)
end
end
Bạn có thể xác định nhiều hơn một chủ đề được đặt tên. Chủ thể được đặt tên được xác định gần đây nhất là chủ thể ẩn danh subject
.
Tuy nhiên, chủ đề được xác định,
Nó được tạo ra một cách lười biếng. Có nghĩa là, sự khởi tạo ngầm định của lớp được mô tả hoặc việc thực thi khối được truyền tới subject
sẽ không xảy ra cho đến khi subject
hoặc chủ thể được đặt tên được tham chiếu trong một ví dụ. Nếu bạn muốn chủ đề hết hạn của mình được khởi tạo một cách háo hức (trước khi một ví dụ trong nhóm chạy), hãy nói subject!
thay vì subject
.
Kỳ vọng có thể được đặt ra trên đó một cách ngầm định (không cần viết subject
hoặc tên của một chủ đề được đặt tên):
describe A do
it { is_expected.to be_an(A) }
end
Chủ đề tồn tại để hỗ trợ cú pháp một dòng này.
Khi nào sử dụng nó
subject
Khó hiểu một ẩn ý (suy ra từ nhóm ví dụ) vì
- Nó được tạo ngay sau hậu trường.
- Cho dù nó được sử dụng ngầm (bằng cách gọi
is_expected
mà không có người nhận rõ ràng) hay rõ ràng (dưới dạng subject
), nó không cung cấp cho người đọc thông tin về vai trò hoặc bản chất của đối tượng mà kỳ vọng đang được gọi.
- Cú pháp ví dụ một lớp lót không có mô tả ví dụ (đối số chuỗi
it
trong cú pháp ví dụ thông thường), vì vậy thông tin duy nhất mà người đọc có về mục đích của ví dụ là chính kỳ vọng.
Do đó, chỉ hữu ích khi sử dụng một chủ đề ngầm khi ngữ cảnh có thể được tất cả người đọc hiểu rõ và thực sự không cần mô tả ví dụ . Trường hợp chính tắc đang kiểm tra xác thực ActiveRecord với trình so khớp nêna:
describe Article do
it { is_expected.to validate_presence_of(:title) }
end
Ẩn danh hết hạn subject
(được định nghĩa subject
mà không có tên) tốt hơn một chút, vì người đọc có thể thấy cách nó được khởi tạo, nhưng
- nó vẫn có thể đưa phần khởi tạo của chủ đề khác xa nơi nó được sử dụng (ví dụ: ở đầu nhóm ví dụ với nhiều ví dụ sử dụng nó), điều này vẫn khó theo dõi và
- nó có các vấn đề khác mà chủ thể ngầm hiểu.
Một chủ thể được đặt tên cung cấp một cái tên tiết lộ ý định, nhưng lý do duy nhất để sử dụng một chủ đề được đặt tên thay vì một let
biến là nếu bạn muốn sử dụng chủ đề ẩn danh đôi khi và chúng tôi vừa giải thích lý do tại sao chủ đề ẩn danh khó hiểu.
Vì vậy, việc sử dụng hợp pháp một chủ thể ẩn danh rõ ràng subject
hoặc một chủ thể được đặt tên là rất hiếm .
let
biến
Cách chúng hoạt động
let
các biến giống như các đối tượng được đặt tên ngoại trừ hai điểm khác biệt:
- chúng được định nghĩa bằng
let
/ let!
thay vì subject
/subject!
- họ không đặt ẩn danh
subject
hoặc cho phép các kỳ vọng được gọi ngầm trên đó.
Khi nào sử dụng chúng
Nó hoàn toàn hợp pháp để sử dụng let
để giảm sự trùng lặp giữa các ví dụ. Tuy nhiên, chỉ làm như vậy khi nó không làm mất đi độ rõ ràng của bài kiểm tra. Thời điểm an toàn nhất để sử dụng let
là khi let
mục đích của biến hoàn toàn rõ ràng so với tên của nó (để người đọc không phải tìm định nghĩa, có thể là nhiều dòng, để hiểu từng ví dụ) và nó được sử dụng theo cách tương tự trong mọi ví dụ. Nếu một trong hai điều đó không đúng, hãy xem xét việc xác định đối tượng trong một biến cục bộ cũ thuần túy hoặc gọi một phương thức gốc ngay trong ví dụ.
let!
là rủi ro, bởi vì nó không phải là lười biếng. Nếu ai đó thêm một ví dụ vào nhóm ví dụ có chứa let!
, nhưng ví dụ đó không cần let!
biến,
- ví dụ đó sẽ khó hiểu, vì người đọc sẽ nhìn thấy
let!
biến và tự hỏi liệu nó có ảnh hưởng như thế nào đến ví dụ đó
- ví dụ sẽ chậm hơn mức cần thiết, vì mất nhiều thời gian để tạo
let!
biến thể
Vì vậy, chỉ nên sử dụng let!
trong các nhóm ví dụ nhỏ, đơn giản, nơi ít có khả năng những người viết ví dụ trong tương lai sẽ rơi vào cái bẫy đó.
Sự tôn sùng đơn kỳ vọng mỗi ví dụ
Có một sự lạm dụng phổ biến của các chủ đề hoặc let
các biến đáng để thảo luận riêng. Một số người thích sử dụng chúng như thế này:
describe 'Calculator' do
describe '#calculate' do
subject { Calculator.calculate }
it { is_expected.to be >= 0 }
it { is_expected.to be <= 9 }
end
end
(Đây là một ví dụ đơn giản về phương thức trả về một số mà chúng ta cần hai kỳ vọng, nhưng kiểu này có thể có nhiều ví dụ / kỳ vọng hơn nếu phương thức trả về một giá trị phức tạp hơn cần nhiều kỳ vọng và / hoặc có nhiều tác dụng phụ tất cả đều cần kỳ vọng.)
Mọi người làm điều này vì họ đã nghe nói rằng người ta chỉ nên có một kỳ vọng cho mỗi ví dụ (điều này bị trộn lẫn với quy tắc hợp lệ rằng người ta chỉ nên kiểm tra một lệnh gọi phương thức cho mỗi ví dụ) hoặc vì họ yêu thích sự phức tạp của RSpec. Đừng làm điều đó, cho dù với một chủ đề ẩn danh hoặc có tên hoặc một let
biến! Phong cách này có một số vấn đề:
- Chủ đề ẩn danh không phải là chủ đề của các ví dụ - phương thức là chủ đề. Viết bài kiểm tra theo cách này làm rối loạn ngôn ngữ, khiến bạn khó suy nghĩ hơn.
- Như mọi khi với các ví dụ một dòng, không có chỗ nào để giải thích ý nghĩa của các kỳ vọng.
- Đối tượng phải được xây dựng cho mỗi ví dụ, điều này diễn ra chậm.
Thay vào đó, hãy viết một ví dụ:
describe 'Calculator' do
describe '#calculate' do
it "returns a single-digit number" do
result = Calculator.calculate
expect(result).to be >= 0
expect(result).to be <= 9
end
end
end