Xác định bài kiểm tra đơn vị hữu ích là gì


47

Tôi đã xem qua các tài liệu của phpunit và đi qua đoạn trích sau:

Bạn luôn có thể viết nhiều bài kiểm tra hơn. Tuy nhiên, bạn sẽ nhanh chóng thấy rằng chỉ một phần nhỏ các bài kiểm tra bạn có thể tưởng tượng là thực sự hữu ích. Những gì bạn muốn là viết các bài kiểm tra thất bại mặc dù bạn nghĩ rằng chúng nên hoạt động, hoặc các bài kiểm tra thành công mặc dù bạn nghĩ rằng chúng nên thất bại. Một cách khác để nghĩ về nó là về chi phí / lợi ích. Bạn muốn viết bài kiểm tra sẽ trả lại cho bạn thông tin. - Rich Gamma

Nó làm tôi băn khoăn. Làm thế nào để bạn xác định những gì làm cho một bài kiểm tra đơn vị hữu ích hơn một bài kiểm tra khác, ngoài những điều được nêu trong trích dẫn đó về chi phí / lợi ích. Làm thế nào để bạn đi về việc quyết định đoạn mã nào bạn tạo ra các bài kiểm tra đơn vị? Tôi đang hỏi điều đó bởi vì một trong những trích dẫn đó cũng nói:

Vì vậy, nếu nó không phải là về thử nghiệm, thì nó là về cái gì? Đó là về việc tìm ra những gì bạn đang cố gắng làm trước khi bạn chạy đi một nửa để cố gắng làm điều đó. Bạn viết một đặc tả mà đóng đinh một khía cạnh nhỏ của hành vi trong một hình thức ngắn gọn, rõ ràng và thực thi. Nó đơn giản mà. Điều đó có nghĩa là bạn viết bài kiểm tra? Không. Điều đó có nghĩa là bạn viết thông số kỹ thuật về những gì mã của bạn sẽ phải làm. Nó có nghĩa là bạn xác định hành vi của mã của bạn trước thời hạn. Nhưng không đi trước thời đại. Trong thực tế, ngay trước khi bạn viết mã là tốt nhất bởi vì đó là khi bạn có nhiều thông tin trong tay như bạn sẽ làm cho đến thời điểm đó. Giống như TDD được thực hiện tốt, bạn làm việc theo từng bước nhỏ ... chỉ định một khía cạnh nhỏ của hành vi tại một thời điểm, sau đó thực hiện nó. Khi bạn nhận ra rằng đó là tất cả về việc chỉ định hành vi và không viết bài kiểm tra, quan điểm của bạn thay đổi quan điểm. Đột nhiên ý tưởng có một lớp Test cho mỗi lớp sản xuất của bạn bị giới hạn một cách lố bịch. Và ý nghĩ thử nghiệm từng phương pháp của bạn bằng phương pháp thử nghiệm riêng (trong mối quan hệ 1-1) sẽ rất buồn cười. - Astave Astels

Phần quan trọng của điều đó là

* Và ý nghĩ thử nghiệm từng phương pháp của bạn bằng phương pháp thử nghiệm riêng (trong mối quan hệ 1-1) sẽ rất buồn cười. *

Vì vậy, nếu việc tạo một bài kiểm tra cho mỗi phương pháp là 'đáng cười', làm thế nào / khi nào bạn chọn những gì bạn viết bài kiểm tra?


5
Đó là một câu hỏi hay, nhưng tôi nghĩ đó là một câu hỏi độc lập với ngôn ngữ lập trình - tại sao bạn lại gắn thẻ php?

Dưới đây là một số bài viết thực sự tốt cung cấp cho tôi một hướng tốt về bài kiểm tra đơn vị nào tôi nên viết và lĩnh vực nào là quan trọng để cung cấp bài kiểm tra tự động cho. - blog.stevensanderson.com/2009/11/04/... - blog.stevensanderson.com/2009/08/24/... - ayende.com/blog/4218/scenario-driven-tests
Kane

Câu trả lời:


27

Có bao nhiêu bài kiểm tra cho mỗi phương pháp?

Vâng, mức tối đa lý thuyết và không thực tế cao là độ phức tạp N-Path (giả sử tất cả các thử nghiệm bao gồm các cách khác nhau thông qua mã;)). Tối thiểu là MỘT!. Theo phương thức công khai , anh ta không kiểm tra chi tiết triển khai, chỉ các hành vi bên ngoài của một lớp (trả về giá trị & gọi các đối tượng khác).

Bạn trích dẫn:

* Và ý nghĩ thử nghiệm từng phương pháp của bạn bằng phương pháp thử nghiệm riêng (trong mối quan hệ 1-1) sẽ rất buồn cười. *

và sau đó hỏi:

Vì vậy, nếu việc tạo một bài kiểm tra cho mỗi phương pháp là 'đáng cười', làm thế nào / khi nào bạn chọn những gì bạn viết bài kiểm tra?

Nhưng tôi nghĩ bạn đã hiểu nhầm tác giả ở đây:

Ý tưởng có one test methodper one method in the class to testlà cái mà tác giả gọi là "buồn cười".

(Ít nhất là đối với tôi) Nó không phải là về 'ít' mà là về 'nhiều hơn'

Vì vậy, hãy để tôi nói lại như tôi hiểu anh ấy:

Và ý nghĩ thử nghiệm từng phương pháp của bạn với CHỈ MỘT PHƯƠNG PHÁP (phương pháp thử nghiệm riêng của nó trong mối quan hệ 1-1) sẽ rất buồn cười.

Để trích dẫn lại trích dẫn của bạn:

Khi bạn nhận ra rằng đó là tất cả về việc chỉ định hành vi và không viết bài kiểm tra, quan điểm của bạn sẽ thay đổi.


Khi bạn thực hành TDD, bạn không nghĩ :

Tôi có một phương pháp calculateX($a, $b);và nó cần một bài kiểm tra kiểm testCalculcateXtra MỌI THỨ về phương pháp đó.

Những gì TDD nói với bạn là suy nghĩ về những gì mã của bạn NÊN LÀM :

Tôi cần tính toán giá trị lớn hơn của hai giá trị ( trường hợp thử nghiệm đầu tiên! ) Nhưng nếu $ a nhỏ hơn 0 thì sẽ tạo ra lỗi ( trường hợp thử nghiệm thứ hai! ) Và nếu $ b nhỏ hơn 0 thì nên .... ( trường hợp thử nghiệm thứ ba! ) và như vậy.


Bạn muốn kiểm tra các hành vi, không chỉ các phương thức đơn lẻ mà không có ngữ cảnh.

Bằng cách đó, bạn nhận được một bộ kiểm tra là tài liệu cho mã của mình và THỰC SỰ giải thích những gì nó dự kiến ​​sẽ làm, thậm chí có thể tại sao :)


Làm thế nào để bạn đi về việc quyết định đoạn mã nào bạn tạo ra các bài kiểm tra đơn vị?

Vâng tất cả mọi thứ kết thúc trong kho lưu trữ hoặc bất cứ nơi nào gần sản xuất đều cần một bài kiểm tra. Tôi không nghĩ rằng tác giả của các trích dẫn của bạn sẽ không đồng ý với điều đó khi tôi cố gắng nêu ở trên.

Nếu bạn không có bài kiểm tra cho việc thay đổi mã sẽ khó hơn (tốn kém hơn), đặc biệt nếu đó không phải là bạn thực hiện thay đổi.

TDD là một cách để đảm bảo rằng bạn có các bài kiểm tra cho MỌI THỨ nhưng miễn là bạn VIẾT các bài kiểm tra thì không sao. Thường thì viết chúng vào cùng một ngày sẽ giúp ích vì bạn sẽ không làm điều đó sau này, phải không? :)



Phản hồi ý kiến:

một số lượng lớn các phương thức không thể được kiểm tra trong một bối cảnh cụ thể vì chúng phụ thuộc hoặc phụ thuộc vào các phương thức khác

Vâng, có ba điều mà các phương thức có thể gọi:

Phương pháp công khai của các lớp khác

Chúng ta có thể giả định các lớp khác vì vậy chúng ta đã xác định trạng thái ở đó. Chúng tôi đang kiểm soát bối cảnh để đó không phải là vấn đề ở đó.

* Các phương thức được bảo vệ hoặc riêng tư trên cùng *

Mọi thứ không phải là một phần của API công khai của một lớp thường không được kiểm tra trực tiếp.

Bạn muốn kiểm tra hành vi và không thực hiện và nếu một lớp thực hiện tất cả thì nó hoạt động theo một phương thức công khai lớn hoặc trong nhiều phương thức được bảo vệ nhỏ hơn được gọi là triển khai . Bạn muốn có thể THAY ĐỔI các phương pháp được bảo vệ đó mà KHÔNG chạm vào các bài kiểm tra của bạn. Bởi vì các bài kiểm tra của bạn sẽ bị hỏng nếu mã của bạn thay đổi hành vi! Đó là những gì bài kiểm tra của bạn dành cho, để cho bạn biết khi bạn phá vỡ một cái gì đó :)

Phương thức công khai trên cùng một lớp

Điều đó không xảy ra rất thường xuyên phải không? Và nếu nó giống như trong ví dụ sau, có một vài cách xử lý việc này:

$stuff = new Stuff();
$stuff->setBla(12);
$stuff->setFoo(14);
$stuff->execute(); 

Rằng các setters tồn tại và không phải là một phần của chữ ký phương thức thực thi là một chủ đề khác;)

Những gì chúng ta có thể kiểm tra ở đây là nếu các lệnh thực thi nổ tung khi chúng ta đặt các giá trị sai. Điều đó setBlađưa ra một ngoại lệ khi bạn vượt qua một chuỗi có thể được kiểm tra riêng nhưng nếu chúng tôi muốn kiểm tra hai giá trị được phép đó (12 & 14) thì không hoạt động TOGETHER (vì bất kỳ lý do gì) so với một trường hợp kiểm tra.

Nếu bạn muốn có một bộ kiểm tra "tốt", bạn có thể, trong php, có thể (!) Thêm một @covers Stuff::executechú thích để đảm bảo bạn chỉ tạo phạm vi bảo hiểm mã cho phương thức này và các công cụ khác chỉ cần thiết lập phải được kiểm tra riêng (một lần nữa, nếu bạn muốn thứ kia).

Vì vậy, vấn đề là: Có thể bạn cần tạo ra một số thế giới xung quanh trước tiên nhưng bạn sẽ có thể viết các trường hợp thử nghiệm có ý nghĩa thường chỉ bao gồm một hoặc có thể hai chức năng thực (setters không được tính ở đây). Phần còn lại có thể bị chế nhạo ether hoặc được kiểm tra trước và sau đó dựa vào (xem @depends)


* Lưu ý: Câu hỏi được di chuyển từ SO và ban đầu là về PHP / PHPUnit, đó là lý do tại sao mã mẫu và tài liệu tham khảo đến từ thế giới php, tôi nghĩ rằng điều này cũng có thể áp dụng cho các ngôn ngữ khác vì phpunit không khác nhiều so với xUnit khác khung kiểm tra.


Rất chi tiết và nhiều thông tin ... Bạn đã nói "Bạn muốn kiểm tra các hành vi, không chỉ các phương thức đơn lẻ mà không có ngữ cảnh.", Chắc chắn một số lượng lớn các phương thức không thể được kiểm tra trong một ngữ cảnh cụ thể vì chúng phụ thuộc hoặc phụ thuộc vào các phương thức khác , do đó, một điều kiện thử nghiệm hữu ích sẽ chỉ theo ngữ cảnh nếu những người phụ thuộc cũng đang được thử nghiệm? Hoặc tôi đang hiểu sai ý của bạn>
zcourts

@ robinsonc494 Tôi sẽ chỉnh sửa trong một ví dụ có thể giải thích rõ hơn một chút về việc tôi sẽ làm gì với điều này
edorian

cảm ơn các chỉnh sửa và ví dụ, nó chắc chắn sẽ giúp. Tôi nghĩ rằng sự nhầm lẫn của tôi (nếu bạn có thể gọi nó như vậy) là mặc dù tôi đã đọc về kiểm tra "hành vi", nhưng bằng cách nào đó tôi chỉ nghĩ về các trường hợp thử nghiệm tập trung vào việc thực hiện.
zcourts

@ robinsonc494 Có thể nghĩ về nó theo cách này: Nếu bạn đấm ai đó, anh ta sẽ đấm lại, gọi cảnh sát hoặc bỏ chạy. Hành vi đó. Đó là những gì Người làm. Việc anh ta sử dụng vẹm của mình được kích hoạt bởi một ít điện tích từ não anh ta đang thực hiện. Nếu bạn muốn kiểm tra phản ứng của ai đó, bạn đấm anh ta và xem anh ta có hành động như bạn mong đợi không. Bạn không đặt anh ta vào một máy quét não và xem liệu các xung động được gửi đến trai. Một số đi cho các lớp học khá nhiều;)
edorian

3
Tôi nghĩ rằng ví dụ tốt nhất tôi thấy về TDD thực sự đã giúp nó nhấp vào cách viết các trường hợp thử nghiệm là Trò chơi Bowling Kata của chú Bob Martin. slideshare.net/lalitkale/bowling-game-kata-by-robert-c-martin
Amy Anuszewski

2

Kiểm tra và kiểm tra đơn vị không giống nhau. Kiểm thử đơn vị là một tập hợp con rất quan trọng và thú vị của Kiểm tra tổng thể. Tôi khẳng định rằng trọng tâm của Kiểm thử đơn vị khiến chúng tôi suy nghĩ về loại thử nghiệm này theo những cách hơi mâu thuẫn với các trích dẫn ở trên.

Đầu tiên, nếu chúng tôi tuân theo TDD hoặc thậm chí DTH (nghĩa là phát triển và thử nghiệm hài hòa), chúng tôi đang sử dụng các bài kiểm tra mà chúng tôi viết để tập trung vào việc thiết kế đúng. Bằng cách suy nghĩ về các trường hợp góc và viết bài kiểm tra phù hợp, chúng tôi tránh được các lỗi xâm nhập ngay từ đầu, vì vậy trên thực tế, chúng tôi viết bài kiểm tra mà chúng tôi dự kiến ​​sẽ vượt qua (OK ngay khi bắt đầu TDD, chúng thất bại, nhưng đó chỉ là một vật phẩm đặt hàng, khi mã được thực hiện, chúng tôi hy vọng chúng sẽ vượt qua và hầu hết đều làm được, vì bạn đã nghĩ về mã.

Thứ hai, các bài kiểm tra đơn vị thực sự trở thành của riêng họ khi chúng tôi tái cấu trúc. Chúng tôi thay đổi việc thực hiện nhưng hy vọng các câu trả lời sẽ giữ nguyên - Bài kiểm tra đơn vị là sự bảo vệ của chúng tôi chống lại việc phá vỡ hợp đồng giao diện của chúng tôi. Vì vậy, một lần nữa chúng tôi mong đợi các bài kiểm tra vượt qua.

Điều này không ngụ ý rằng đối với giao diện công cộng của chúng tôi, có lẽ là ổn định, chúng tôi cần có khả năng truy nguyên rõ ràng để chúng tôi có thể thấy rằng mọi phương thức công khai đều được thử nghiệm.

Để trả lời câu hỏi rõ ràng của bạn: Kiểm tra đơn vị cho giao diện công cộng có giá trị.

chỉnh sửa trong bình luận phản hồi:

Thử nghiệm phương pháp riêng? Vâng, chúng ta nên, nhưng nếu chúng ta không phải kiểm tra một cái gì đó thì đó là nơi tôi thỏa hiệp. Rốt cuộc nếu các phương thức công cộng đang hoạt động thì những lỗi đó trong các công cụ riêng tư có thể rất quan trọng? Về mặt thực tế, sự hỗn loạn có xu hướng xảy ra trong các công cụ riêng tư, bạn làm việc chăm chỉ để duy trì giao diện công cộng của mình, nhưng nếu những thứ bạn phụ thuộc vào thay đổi thì những thứ riêng tư có thể thay đổi. Tại một số điểm chúng tôi có thể thấy việc duy trì các bài kiểm tra nội bộ là rất nhiều nỗ lực. Là nỗ lực đó chi tiêu tốt?


Vì vậy, để chắc chắn rằng tôi hiểu những gì bạn đang nói: Khi kiểm tra, hãy tập trung vào kiểm tra giao diện công cộng phải không? Giả sử điều đó đúng ... không có khả năng lớn hơn để lại lỗi trong các phương thức / giao diện riêng tư mà bạn không thực hiện kiểm tra đơn vị, một số lỗi khó khăn trong giao diện "riêng tư" chưa được kiểm tra có thể dẫn đến thử nghiệm vượt qua khi nó nên đã thực sự thất bại. Có phải tôi đã sai khi nghĩ như vậy?
zcourts

Sử dụng phạm vi bảo hiểm mã bạn có thể biết khi nào mã trong các phương thức riêng tư của bạn không được thực thi trong khi kiểm tra các phương thức công khai của bạn. Nếu các phương thức công khai của bạn được bảo hiểm đầy đủ, mọi phương thức riêng tư chưa được khám phá rõ ràng không được sử dụng và có thể được gỡ bỏ. Nếu không, bạn cần thử nghiệm nhiều hơn cho các phương pháp công khai của bạn.
David Harkness

2

Các bài kiểm tra đơn vị nên là một phần của chiến lược thử nghiệm lớn hơn. Tôi tuân theo các nguyên tắc này trong việc chọn loại bài kiểm tra để viết và khi nào:

  • Tập trung vào viết bài kiểm tra đầu cuối. Bạn bao gồm nhiều mã hơn cho mỗi bài kiểm tra so với các bài kiểm tra đơn vị và do đó nhận được nhiều bài kiểm tra hơn cho buck. Làm cho các xác nhận tự động toàn bộ hệ thống của bạn và toàn bộ hệ thống của bạn.

  • Thả xuống để viết các bài kiểm tra đơn vị xung quanh các logic phức tạp. Các bài kiểm tra đơn vị có giá trị trọng lượng của chúng trong các tình huống trong đó các bài kiểm tra đầu cuối sẽ khó gỡ lỗi hoặc khó sử dụng để viết cho phạm vi bảo hiểm mã đầy đủ.

  • Đợi cho đến khi API bạn đang kiểm tra ổn định để viết một trong hai loại thử nghiệm. Bạn muốn tránh phải cấu trúc lại cả việc thực hiện và kiểm tra của bạn.

Rob Ashton có một bài viết hay về chủ đề này, mà tôi đã rút ra rất nhiều để nói rõ các nguyên tắc trên.


+1 - Tôi không nhất thiết phải đồng ý với tất cả các điểm của bạn (hoặc điểm của bài viết) nhưng tôi đồng ý rằng hầu hết các bài kiểm tra đơn vị đều vô dụng nếu được thực hiện một cách mù quáng (phương pháp TDD). Tuy nhiên, chúng cực kỳ có giá trị nếu bạn thông minh trong việc quyết định những gì xứng đáng dành thời gian làm bài kiểm tra đơn vị. Tôi hoàn toàn đồng ý rằng bạn sẽ nhận được rất nhiều, rất nhiều cho việc viết các bài kiểm tra cấp cao hơn, đặc biệt là kiểm tra tự động ở cấp hệ thống con. Vấn đề với các thử nghiệm tự động đầu cuối là chúng sẽ khó, nếu không hoàn toàn không thực tế, đối với một hệ thống nếu nó có bất kỳ kích thước / độ phức tạp nào.
Dunk

0

Tôi có xu hướng theo một cách tiếp cận khác để kiểm tra đơn vị có vẻ hoạt động tốt. Thay vì nghĩ về một bài kiểm tra đơn vị là "Kiểm tra một số hành vi", tôi nghĩ về nó nhiều hơn là "một đặc tả mà mã của tôi phải tuân theo". Theo cách này, về cơ bản, bạn có thể tuyên bố rằng một đối tượng nên hành xử theo một cách nhất định và cho rằng bạn cho rằng ở nơi khác trong chương trình của mình, bạn có thể khá chắc chắn rằng nó tương đối không có lỗi.

Nếu bạn đang viết API công khai, điều này cực kỳ có giá trị. Tuy nhiên, bạn sẽ luôn cần một lượng thử nghiệm tích hợp đầu cuối tốt vì tiếp cận phạm vi kiểm tra đơn vị 100% thường không đáng và sẽ bỏ lỡ những điều mà hầu hết sẽ coi là "không thể kiểm chứng" bằng các phương pháp kiểm tra đơn vị (chế giễu, Vân vân)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.