Chain RSpec Matchers for Improved Test Readability
Bài đăng này đã không được cập nhật trong 6 năm
Một trong những đặc điểm mà nhiều người thích ở Ruby
đó chính là khả năng Readability
của Ruby
code. Vì vậy, một người code Ruby
hay là người có khả năng làm code cho họ dễ đọc nhất có thể.
Original Code
select_multiple_from "Which of these apply to you?", [
"I read the New York Times every day",
"I read the Washington Post every day",
]
click_on "Submit"
expect(page).to have_css("dd ul li", count: 2)
expect(page).to have_css("dd ul li", text: "I read the New York Times every day")
expect(page).to have_css("dd ul li", text: "I read the Washington Post every day")
nhiệm vụ của method select_multiple_from
là handle multi-select
def select_multiple_from from, options
options.each do |option|
select option, from: from
end
end
Refactor
3 dòng assertion
ở trên có vẻ là không có ý nghĩa cho lắm, nhưng nó là cần thiết:
- Đảm bảo số lượng item được chọn trong
multi-select
là chính xác, không thừa, không thiếu
Khi viết Ruby
code, đặc biệt là Ruby
code focus vào acceptance test, tôi thường xuyên focus vào tính Readability
của nó.
expect(page).to have_multiple_choice_responses(
"I read the New York Times every day",
"I read the Washington Post every day"
)
Với đoạn code trên chúng ta sẽ cover rằng chỉ có 2 và chỉ 2 items xuất hiện trong list. Nhưng trong trường hợp chúng ta không chỉ cover số lượng item xuất hiện, chúng ta có thể sử dụng featureand của Rspec
. Khi sử dụng với have_css
của Capybara
chúng ta có thể refactor lại code trên như sau:
def have_multiple_choice_responses(item1, item2)
have_css("dd ul li", count: 2).
and(have_css("dd ul li", text: item1)).
and(have_css("dd ul li", text: item2))
end
Nhưng 1 lần nữa, đoạn code trên lại gặp vấn đến với số lượng item. Chúng ta sẽ cover trường hợp đó với: Enumrable inject
def have_multiple_choice_responses(*args)
count_matcher = have_css("dd ul li", count: args.length)
args.inject(count_matcher) do |matcher, text|
matcher.and(have_css("dd ul li", text: text))
end
end
Đoạn code trên cover được trường hợp list có chứa đầy đủ các item, trường hợp chúng ta muốn cover thêm trường hợp thứ tự của các item đó trong list:
def have_multiple_choice_responses(*args)
count_matcher = have_css("dd ul li", count: args.length)
args.each.with_index(1).inject(count_matcher) do |matcher, (text, offset)|
matcher.and(have_css("dd ul li:nth-of-type(#{offset})", text: text))
end
end
Do là li:nth-of-type
có offset là 1
nên ta phải sử dụng with_index(1)
Conclusion
Với đoạn code đã refactor ở trên, chúng ta đã sửa dụng Rspec
với Ruby
để tạo ra các assertion dễ đọc, dễ maintenance.
Thanks for reading.
Happy coding!
Refs
https://robots.thoughtbot.com/chain-rspec-matchers-for-improved-test-readability
All rights reserved