Bài này về Question cách screenplay compare kết quả, có rất nhiều thứ để học tập. Nếu bạn đọc xong mà không hiểu thì bạn biết là có rất nhiều thứ bạn phải học. 😀
Chúng ta hãy bắt đầu từ 1 ví dụ đơn giản:
@Test public void should_see_how_to_begin() { ... then(james).should(seeThat(Placeholder.text(), is("What needs to be done?"))); }
Nội dung bài viết
I. Phân tích
then(james) --> james
bởi vì
public static Actor then(Actor actor) { return actor; }
Như các bài trước mình đã từng nói givenThat(), when(), then()
chỉ mục đích làm cho code giống câu văn.
Note cho bạn nào chưa biết: cái chữ T gọi là type parameter
trong Java generics
public static <T extends PerformsTasks> T givenThat(T actor) { return actor; } public static Actor andThat(Actor actor) {return actor; } public static Actor when(Actor actor) { return actor; } public static Actor then(Actor actor) { return actor; } public static Actor and(Actor actor) { return actor; } public static Actor but(Actor actor) { return actor; }
.should()
sẽ thực hiện việc so sánh, nó tiếp nhận 1 hoặc nhiều objectConsequence
, sau đó nó sẽforEach
để so sánh từng cái một.
public final void should(Consequence... consequences) { (1) .... for (Consequence consequence : consequences) { check(consequence, errorTally); } .... }
- Làm thế nào để có các object
Consequence
này, đó là lúc các methodseeThat()
của classGivenWhenThen
vào cuộc. ClassGivenWhenThen
bây giờ đóng vai trò là 1 simple Factory (bạn có thể tìm hiểu thêm về Factory Method pattern), mình viết ví dụ 2 methods thôi.
... public static <T> Consequence<T> seeThat(Question<? extends T> actual, Matcher<T> expected){ return new QuestionConsequence(actual, expected); (2) } public static <T> Consequence<T> seeThat(Question<? extends T> actual, Predicate<T> expected) { return new PredicateConsequence(actual, expected); (3) } ...
Hãy nhìn vào bên trong code, mình có đánh dấu (1), (2), (3).
Note cho bạn nào chưa biết: (Consequence… consequences)
gọi là varagrs
Tại sao trên mục (1), method should(Consequence… consequences)
nhận Consequence
mà (2) lại return QuestionConsequence
và (3) return PredicateConsequence
?
Vì chúng có quan hệ cha-con, “con” có thể thay thế cho “cha”, đây là 1 đặc điểm trong tính thừa kế trong java thừa kế Type.
Placeholder.text()
sẽ tạo raQuestion<T>
is("What needs to be done?")
là Matcher của thư viện Hamcrest Matcher.
II. Đi sâu vào cách screenplay so sánh
Phần trước, chúng ta đã biết là đoạn code để thực hiện so sánh chính là
check(consequence, errorTally);
Nó sẽ gọi đến đoạn code sau đây:
private <T> void check(Consequence<T> consequence, ErrorTally errorTally) { ... consequence.evaluateFor(this); ... }
Đến đây thì nó sẽ gọi đến phần implementation method evaluateFor
của từng loại Consequence
theo tính chất của polymophism (đa hình).
void evaluateFor(Actor actor)
Theo ví dụ ở phía trên:
seeThat(Placeholder.text(), is("What needs to be done?"))
sẽ map vào
public static <T> Consequence<T> seeThat(Question<? extends T> actual, Matcher<T> expected) {
return new QuestionConsequence(actual, expected);
}
Do vậy, nó sẽ tạo ra QuestionConsequence
. Và đây là phần implementation evaluateFor
import static org.hamcrest.MatcherAssert.assertThat; @Override public void evaluateFor(Actor actor) { ... assertThat(question.answeredBy(actor), expected); ... }
Cuối cùng thì ta cũng thấy là thực chất thì screenplay sử dụng assertion của Hamcrest Matcher.
Ta hoàn toàn có thể viết lại test như sau mà ý nghĩa không thay đổi.
@Test public void should_see_how_to_begin() { ... assertThat(Placeholder.text().answeredBy(james), is("What needs to be done?")); } //or @Test public void should_see_how_to_begin() { ... String placeholderText = Placeholder.text().answeredBy(james); assertThat(placeholderText, is("What needs to be done?")); }
III. Cách tạo ra question
Question<T>
là 1 object mà sẽ chứa bên trong nó 1 object khác, như đã nói ở trên, T là generics type, có nghĩa là nó thể là object nào cũng được. Nó giống như List<T>
thôi. Ví dụ:
Question<String>
Question<Integer>
Question<Infomation>
- ….
Trong ví dụ trên Placeholder.text()
–> Question<String>
. Tất cả các class con của class Question<T>
sẽ phải implement method
T answeredBy(Actor actor);
do đó, khi Placeholder.text().answeredBy(james)
sẽ đươc hiểu là:
Có rất nhiều cách để tạo ra question, bạn có thể tham khảo ở đây
IV. Tổng kết
Mình đã đi vào những phần cơ bản của code bên trong thư viện screenplay, hi vọng đem thêm 1 chút thông tin cho các bạn đang muốn học và làm UI automation test mà dùng đến screenplay của framework serenity.
- Nếu bạn thấy hay thì đừng ngại ngần cho 1 like ủng hộ tinh thần.
- Nếu bạn không hiểu gì thì việc đọc đến những dòng này cũng thể hiện độ “lì lợm” của bạn, bạn rất xứng đáng 1 cốc nước lọc. =)))))
Bạn nào muốn nâng cấp trình độ code java, để có thể đọc hiểu phần nào code thư viện mà bạn sử dụng, hãy đăng ký khóa học Java Intermediate của mình.