Làm thế nào để bạn phát hiện các vấn đề phụ thuộc với các bài kiểm tra đơn vị khi bạn sử dụng các đối tượng giả?


98

Bạn có một lớp X và bạn viết một số bài kiểm tra đơn vị xác minh hành vi X1. Ngoài ra còn có lớp A lấy X làm phụ thuộc.

Khi bạn viết bài kiểm tra đơn vị cho A, bạn giả định X. Nói cách khác, trong khi kiểm tra đơn vị A, bạn đặt (định nghĩa) hành vi của giả của X là X1. Thời gian trôi qua, mọi người sử dụng hệ thống của bạn, cần thay đổi, X phát triển: bạn sửa đổi X để hiển thị hành vi X2. Rõ ràng, các bài kiểm tra đơn vị cho X sẽ thất bại và bạn sẽ cần phải điều chỉnh chúng.

Nhưng với A thì sao? Các thử nghiệm đơn vị cho A sẽ không thất bại khi hành vi của X bị sửa đổi (do chế nhạo X). Làm cách nào để phát hiện kết quả của A sẽ khác khi chạy với X "thực" (đã sửa đổi)?

Tôi đang mong đợi câu trả lời dọc theo dòng chữ: "Đó không phải là mục đích của thử nghiệm đơn vị", nhưng thử nghiệm đơn vị có giá trị gì? Có thực sự chỉ cho bạn biết rằng khi tất cả các bài kiểm tra vượt qua, bạn đã không đưa ra một thay đổi đột phá? Và khi hành vi của một số lớp thay đổi (sẵn sàng hoặc không sẵn lòng), làm thế nào bạn có thể phát hiện (tốt nhất là theo cách tự động) tất cả các hậu quả? Chúng ta không nên tập trung nhiều hơn vào thử nghiệm tích hợp?



36
Ngoài tất cả các câu trả lời gợi ý, tôi phải nói rằng tôi không đồng ý với tuyên bố sau: 'Liệu nó thực sự chỉ nói với bạn rằng khi tất cả các xét nghiệm vượt qua, bạn đã không giới thiệu một sự thay đổi phá vỡ?' Nếu bạn thực sự nghĩ rằng việc loại bỏ nỗi sợ tái cấu trúc là rất ít giá trị, thì bạn đang trên đường nhanh chóng hướng tới việc viết mã không thể
nhầm lẫn

5
Kiểm thử đơn vị cho bạn biết liệu đơn vị mã của bạn có hoạt động như bạn mong đợi hay không. Không nhiều hơn hoặc ít hơn. Giả và đôi kiểm tra cung cấp một môi trường nhân tạo, được kiểm soát để bạn thực hiện đơn vị mã (cách ly) để xem liệu nó có đáp ứng mong đợi của bạn không. Không nhiều hơn hoặc ít hơn.
Robert Harvey

2
Tôi tin rằng tiền đề của bạn là không chính xác. Khi bạn đề cập đến X1bạn đang nói rằng Xthực hiện giao diện X1. Nếu bạn thay đổi giao diện X1thành X2giả mà bạn đã sử dụng trong các thử nghiệm khác thì không nên biên dịch nữa, do đó bạn cũng buộc phải sửa các thử nghiệm đó. Thay đổi trong hành vi lớp học không nên quan trọng. Trong thực tế, lớp của bạn Akhông nên phụ thuộc vào chi tiết triển khai (đó là những gì bạn sẽ thay đổi trong trường hợp đó). Vì vậy, các bài kiểm tra đơn vị Avẫn đúng và chúng cho bạn biết rằng Acác công việc được đưa ra thực hiện lý tưởng của giao diện.
Bakuriu

5
Tôi không biết về bạn, nhưng khi tôi phải làm việc với một cơ sở mã hóa mà không có bài kiểm tra nào, tôi sợ đến chết tôi sẽ phá vỡ một cái gì đó. Và tại sao? Bởi vì nó xảy ra thường xuyên đến nỗi một cái gì đó bị phá vỡ khi nó không được dự định. Và ban phước cho trái tim người thử nghiệm của chúng tôi, họ không thể kiểm tra tất cả mọi thứ. Hoặc thậm chí gần gũi. Nhưng một bài kiểm tra đơn vị sẽ vui vẻ chug đi qua thói quen nhàm chán sau thói quen nhàm chán.
corsiKa

Câu trả lời:


125

Khi bạn viết bài kiểm tra đơn vị cho A, bạn giả định X

Phải không Tôi không, trừ khi tôi thực sự phải làm. Tôi phải nếu:

  1. X chậm, hoặc
  2. X có tác dụng phụ

Nếu cả hai không áp dụng, thì bài kiểm tra đơn vị của tôi Acũng sẽ kiểm tra X. Làm bất cứ điều gì khác sẽ làm các bài kiểm tra cô lập đến một cực kỳ phi logic.

Nếu bạn có các phần trong mã của mình bằng cách sử dụng các phần khác của mã, thì tôi đồng ý: điểm của các bài kiểm tra đơn vị đó là gì? Vì vậy, đừng làm điều này. Hãy để những bài kiểm tra sử dụng các phụ thuộc thực sự khi chúng tạo thành các bài kiểm tra có giá trị hơn nhiều theo cách đó.

Và nếu một số người khó chịu khi bạn gọi các bài kiểm tra này, "bài kiểm tra đơn vị", thì chỉ cần gọi chúng là "bài kiểm tra tự động" và tiếp tục viết bài kiểm tra tự động tốt.


94
@Laiv, Không, các bài kiểm tra đơn vị được cho là hoạt động như một đơn vị, tức là chạy trong sự cô lập, từ các bài kiểm tra khác . Các nút và đồ thị có thể đi bộ. Nếu tôi có thể chạy thử nghiệm đầu cuối miễn phí, hiệu ứng phụ bị cô lập trong một thời gian ngắn, đó là thử nghiệm đơn vị. Trong trường hợp bạn không thích định nghĩa đó, hãy gọi nó là kiểm tra tự động và ngừng viết các bài kiểm tra tào lao để phù hợp với ngữ nghĩa ngớ ngẩn.
David Arno

9
@DavidArno Có một định nghĩa rất rộng về sự cô lập. Một số người muốn có một "đơn vị" để bao gồm tầng giữa và cơ sở dữ liệu. Họ có thể tin bất cứ điều gì họ thích nhưng cơ hội là trên một sự phát triển ở bất kỳ kích thước nào, các bánh xe sẽ xuất hiện theo thứ tự khá ngắn vì người quản lý xây dựng sẽ ném nó ra. Nói chung, nếu họ bị cô lập với hội đồng (hoặc tương đương), điều đó là tốt. NB nếu bạn mã hóa các giao diện thì việc thêm chế độ giả và DI sau này dễ dàng hơn nhiều.
Robbie Dee

13
Bạn đang ủng hộ cho một loại bài kiểm tra khác thay vì trả lời câu hỏi. Đó là một điểm hợp lệ, nhưng đây là một cách khá khéo léo để làm điều đó.
Phil Frost

17
@PhilFrost, để tự trích dẫn: " Và nếu một số người khó chịu khi bạn gọi các bài kiểm tra này," bài kiểm tra đơn vị ", thì hãy gọi chúng là" bài kiểm tra tự động "và viết bài kiểm tra tự động tốt. " Viết bài kiểm tra hữu ích, không phải bài kiểm tra ngớ ngẩn điều đó chỉ đơn giản là đáp ứng một số định nghĩa ngẫu nhiên của một từ. Hoặc cách khác, chấp nhận rằng có thể bạn đã định nghĩa sai về "kiểm tra đơn vị" và bạn đã sử dụng giả vì bạn đã sai. Dù bằng cách nào, bạn sẽ kết thúc với các bài kiểm tra tốt hơn.
David Arno

30
Tôi với @DavidArno về điều này; chiến lược thử nghiệm của tôi đã thay đổi sau khi xem bài nói chuyện này của Ian Cooper: vimeo.com/68375232 . Để đun sôi nó xuống một câu duy nhất: Đừng kiểm tra các lớp . Kiểm tra hành vi . Các bài kiểm tra của bạn không nên có kiến ​​thức về các lớp / phương thức nội bộ được sử dụng để thực hiện hành vi mong muốn; họ chỉ nên biết bề mặt công khai của API / thư viện của bạn và họ nên kiểm tra điều đó. Nếu các bài kiểm tra có quá nhiều kiến ​​thức thì bạn đang kiểm tra chi tiết thực hiện và các bài kiểm tra của bạn trở nên dễ vỡ, kết hợp với việc thực hiện của bạn và thực sự chỉ là một mỏ neo quanh cổ bạn.
Richiban

79

Bạn cần cả hai. Kiểm tra đơn vị để xác minh hành vi của từng đơn vị của bạn và một vài thử nghiệm tích hợp để đảm bảo chúng được kết nối chính xác. Vấn đề chỉ dựa vào kiểm tra tích hợp là sự bùng nổ tổ hợp do sự tương tác giữa tất cả các đơn vị của bạn.

Giả sử bạn có lớp A, yêu cầu 10 bài kiểm tra đơn vị để bao gồm đầy đủ tất cả các đường dẫn. Sau đó, bạn có một lớp B khác, cũng yêu cầu 10 bài kiểm tra đơn vị để bao quát tất cả các đường dẫn mà mã có thể đi qua nó. Bây giờ, giả sử trong ứng dụng của bạn, bạn cần đưa đầu ra của A vào B. Bây giờ mã của bạn có thể đi theo 100 đường dẫn khác nhau từ đầu vào của A đến đầu ra của B.

Với các bài kiểm tra đơn vị, bạn chỉ cần 20 bài kiểm tra đơn vị + 1 bài kiểm tra tích hợp để hoàn toàn bao gồm tất cả các trường hợp.

Với các bài kiểm tra tích hợp, bạn sẽ cần 100 bài kiểm tra để bao quát tất cả các đường dẫn mã.

Đây là một video rất hay về những nhược điểm của việc chỉ dựa vào các bài kiểm tra tích hợp JB Rainsberger Các bài kiểm tra tích hợp là một trò lừa đảo HD


1
Tôi chắc chắn rằng không phải ngẫu nhiên mà dấu hỏi về hiệu quả của các bài kiểm tra tích hợp đã đi đôi với các bài kiểm tra đơn vị bao gồm mọi lớp nữa.
Robbie Dee

16
Đúng, nhưng không nơi nào bài kiểm tra 20 đơn vị của bạn yêu cầu chế giễu. Nếu bạn có 10 bài kiểm tra A bao gồm tất cả A và 10 bài kiểm tra của bạn bao gồm tất cả B và cũng kiểm tra lại 25% của A như một phần thưởng thì điều này có vẻ như giữa "tốt" và một điều tốt. Mocking A in Bs tests có vẻ chủ động ngu ngốc (trừ khi thực sự có lý do tại sao A là một vấn đề, ví dụ như cơ sở dữ liệu hoặc nó mang lại một mạng lưới dài những thứ khác)
Richard Tingle

9
Tôi không đồng ý với ý kiến ​​rằng một thử nghiệm tích hợp duy nhất là đủ nếu bạn muốn bảo hiểm đầy đủ. Phản ứng của B với những gì đầu ra A sẽ thay đổi dựa trên đầu ra; nếu thay đổi một tham số trong A thay đổi đầu ra của nó, thì B có thể không xử lý chính xác.
Matthieu M.

3
@ Eternal21: Quan điểm của tôi là đôi khi, vấn đề không nằm ở hành vi cá nhân, mà là ở sự tương tác bất ngờ. Đó là, khi keo giữa A và B hành xử bất ngờ trong một số tình huống. Vì vậy, cả A và B đều hoạt động theo thông số kỹ thuật và trường hợp hạnh phúc hoạt động, nhưng trên một số đầu vào có lỗi trong mã keo ...
Matthieu M.

1
@MatthieuM. Tôi cho rằng điều này nằm ngoài phạm vi của Thử nghiệm đơn vị. Mã keo có thể được kiểm tra đơn vị trong khi các tương tác giữa A và B thông qua mã keo là Kiểm tra Tích hợp. Khi các trường hợp cạnh hoặc lỗi cụ thể được tìm thấy, chúng có thể được thêm vào các bài kiểm tra đơn vị mã keo và cuối cùng được xác minh trong kiểm tra Tích hợp.
Andrew T Finnell

72

Khi bạn viết bài kiểm tra đơn vị cho A, bạn giả định X. Nói cách khác, trong khi kiểm tra đơn vị A, bạn đặt (định nghĩa) hành vi của giả của X là X1. Thời gian trôi qua, mọi người sử dụng hệ thống của bạn, cần thay đổi, X phát triển: bạn sửa đổi X để hiển thị hành vi X2. Rõ ràng, các bài kiểm tra đơn vị cho X sẽ thất bại và bạn sẽ cần phải điều chỉnh chúng.

Ái chà, đợi một lát. Ý nghĩa của các thử nghiệm đối với X thất bại là quá quan trọng để vượt qua như thế.

Nếu việc thay đổi triển khai X từ X1 sang X2 sẽ phá vỡ các bài kiểm tra đơn vị cho X, điều đó cho thấy rằng bạn đã thực hiện thay đổi ngược không tương thích với hợp đồng X.

X2 không phải là X, theo nghĩa Liskov , vì vậy bạn nên suy nghĩ về các cách khác để đáp ứng nhu cầu của những người nắm giữ cổ phần của bạn (như giới thiệu một đặc tả Y mới, được X2 triển khai).

Để hiểu sâu hơn, hãy xem Pieter Hinjens: Sự kết thúc của các phiên bản phần mềm hoặc Rich Hickey Simple Made Easy .

Từ quan điểm của A, có một điều kiện tiên quyết là cộng tác viên tôn trọng hợp đồng X. Và quan sát của bạn có hiệu quả là thử nghiệm biệt lập cho A không mang lại cho bạn sự đảm bảo rằng A nhận ra các cộng tác viên vi phạm hợp đồng X.

Xem lại các bài kiểm tra tích hợp là một Scam ; ở mức độ cao, bạn sẽ có nhiều thử nghiệm riêng biệt như bạn cần để đảm bảo rằng X2 thực hiện đúng hợp đồng X và nhiều thử nghiệm bị cô lập như bạn cần để đảm bảo rằng A thực hiện đúng các phản hồi thú vị từ X và một số lượng thử nghiệm tích hợp nhỏ hơn để đảm bảo X2 và A đồng ý với ý nghĩa của X.

Đôi khi bạn sẽ thấy sự khác biệt này được thể hiện dưới dạng thử nghiệm đơn độc so với sociablethử nghiệm; xem Jay Lĩnh vực làm việc hiệu quả với các bài kiểm tra đơn vị .

Chúng ta không nên tập trung nhiều hơn vào thử nghiệm tích hợp?

Một lần nữa, hãy xem các bài kiểm tra tích hợp là một trò lừa đảo - Rainsberger mô tả chi tiết một vòng phản hồi tích cực phổ biến (theo kinh nghiệm của anh ấy) cho các dự án dựa trên các bài kiểm tra tích hợp (ghi chú chính tả). Tóm lại, không có các thử nghiệm biệt lập / đơn độc gây áp lực cho thiết kế , chất lượng xuống cấp, dẫn đến nhiều sai lầm và các thử nghiệm tích hợp hơn ....

Bạn cũng sẽ cần (một số) kiểm tra tích hợp. Ngoài sự phức tạp được giới thiệu bởi nhiều mô-đun, việc thực hiện các thử nghiệm này có xu hướng có nhiều lực cản hơn so với các thử nghiệm bị cô lập; Sẽ hiệu quả hơn khi lặp lại các kiểm tra rất nhanh khi công việc đang được tiến hành, lưu các kiểm tra bổ sung khi bạn nghĩ rằng mình đã "hoàn thành".


8
Đây phải là câu trả lời được chấp nhận. Câu hỏi phác thảo một tình huống trong đó hành vi của một lớp đã được sửa đổi theo cách không tương thích, nhưng bên ngoài trông vẫn giống hệt nhau. Vấn đề ở đây nằm ở thiết kế của ứng dụng chứ không phải các bài kiểm tra đơn vị. Cách tình huống này sẽ được bắt gặp trong thử nghiệm là sử dụng thử nghiệm tích hợp giữa hai lớp đó.
Nick Coad

1
"Không có các thử nghiệm đơn độc / đơn độc gây áp lực cho thiết kế, chất lượng xuống cấp". Tôi nghĩ rằng đây là một điểm quan trọng. Cùng với kiểm tra hành vi, kiểm tra đơn vị có tác dụng phụ để buộc bạn phải có một thiết kế mô-đun hơn.
MickaëlG

Tôi cho rằng điều này hoàn toàn đúng, nhưng điều này giúp tôi như thế nào nếu một phụ thuộc bên ngoài đưa ra một thay đổi không tương thích ngược với hợp đồng X? Có lẽ một lớp thực hiện I / O trong thư viện phá vỡ tính tương thích và chúng tôi đang chế giễu X vì chúng tôi không muốn các bài kiểm tra đơn vị trong CI phụ thuộc vào I / O nặng. Tôi nghĩ OP đang yêu cầu kiểm tra điều này và tôi không hiểu làm thế nào điều này trả lời câu hỏi. Làm thế nào để kiểm tra cho điều này?
gerrit

15

Hãy để tôi bắt đầu bằng cách nói rằng tiền đề cốt lõi của câu hỏi là thiếu sót.

Bạn không bao giờ kiểm tra (hoặc chế nhạo) việc triển khai, bạn đang kiểm tra (và chế nhạo) giao diện .

Nếu tôi có một lớp X thực sự thực hiện giao diện X1, tôi có thể viết một XM giả cũng tuân thủ X1. Sau đó, lớp A của tôi phải sử dụng thứ gì đó thực hiện X1, có thể là lớp X hoặc giả XM.

Bây giờ, giả sử chúng ta thay đổi X để thực hiện giao diện X2 mới. Vâng, rõ ràng mã của tôi không còn biên dịch. A yêu cầu một cái gì đó thực hiện X1 và không còn tồn tại. Vấn đề đã được xác định và có thể được khắc phục.

Giả sử thay vì thay thế X1, chúng tôi chỉ sửa đổi nó. Bây giờ lớp A đã được thiết lập. Tuy nhiên, XM giả không còn thực hiện giao diện X1. Vấn đề đã được xác định và có thể được khắc phục.


Toàn bộ cơ sở để kiểm tra đơn vị và chế nhạo là bạn viết mã sử dụng giao diện. Một người tiêu dùng của một giao diện không quan tâm đến cách mã được thực thi, chỉ có điều hợp đồng đó được tuân thủ (đầu vào / đầu ra).

Điều này bị phá vỡ khi phương pháp của bạn có tác dụng phụ, nhưng tôi nghĩ rằng có thể được loại trừ một cách an toàn vì "không thể được kiểm tra đơn vị hoặc chế giễu".


11
Câu trả lời này làm cho rất nhiều giả định không cần phải giữ. Đầu tiên, giả sử, đại khái là chúng ta đang ở C # hoặc Java (hay chính xác hơn là chúng ta đang ở một ngôn ngữ được biên dịch, ngôn ngữ đó có giao diện và X thực hiện giao diện; không cần điều nào trong số này là đúng). Thứ hai, nó giả định rằng bất kỳ thay đổi nào đối với hành vi hoặc "hợp đồng" của X đều yêu cầu thay đổi giao diện (theo cách hiểu của trình biên dịch) mà X thực hiện. Điều này hoàn toàn không đúng, ngay cả khi chúng ta đang ở trong Java hoặc C #; bạn có thể thay đổi cách thực hiện phương thức mà không thay đổi chữ ký của nó.
Đánh dấu Amery

6
@MarkAmery Đúng là thuật ngữ "giao diện" cụ thể hơn đối với C # hoặc Java, nhưng tôi nghĩ rằng quan điểm giả định một "hợp đồng" hành vi được xác định (và nếu điều đó không được mã hóa thì tự động phát hiện điều này là không thể). Bạn cũng hoàn toàn chính xác rằng việc triển khai có thể được thay đổi mà không cần thay đổi hợp đồng. Nhưng thay đổi để thực hiện mà không thay đổi giao diện (hoặc hợp đồng) sẽ không ảnh hưởng đến bất kỳ người tiêu dùng nào. Nếu hành vi của A phụ thuộc vào cách giao diện (hoặc hợp đồng) được triển khai, thì không thể (có ý nghĩa) kiểm tra đơn vị.
Vlad274

1
"Bạn cũng hoàn toàn chính xác rằng việc triển khai có thể được thay đổi mà không cần thay đổi hợp đồng" - trong khi cũng đúng, đây không phải là điểm tôi đang cố gắng thực hiện. Thay vào đó, tôi đang khẳng định một sự khác biệt giữa hợp đồng (sự hiểu biết của một lập trình viên về những gì một đối tượng phải làm, có lẽ được chỉ định trong tài liệu) và giao diện (một danh sách các chữ ký phương thức, được trình biên dịch hiểu) và nói rằng hợp đồng có thể được thay đổi mà không thay đổi giao diện. Tất cả các chức năng có cùng chữ ký đều có thể hoán đổi cho nhau theo quan điểm của hệ thống loại, nhưng thực tế không phải vậy!
Đánh dấu Amery

4
@MarkAmery: Tôi không nghĩ Vlad đang sử dụng từ "giao diện" theo nghĩa giống như bạn đang sử dụng nó; cách tôi đọc câu trả lời, nó không nói về các giao diện theo nghĩa hẹp C # / Java (nghĩa là một tập hợp các chữ ký phương thức) mà theo nghĩa chung của từ này, như được sử dụng, ví dụ như trong thuật ngữ "giao diện lập trình ứng dụng" hoặc thậm chí " giao diện người dùng". [...]
Ilmari Karonen

6
@IlmariKaronen Nếu Vlad đang sử dụng "giao diện" có nghĩa là "hợp đồng" chứ không phải theo nghĩa hẹp C # / Java, thì câu lệnh "Bây giờ, giả sử chúng ta thay đổi X để thực hiện giao diện X2 mới. Rõ ràng, mã của tôi không còn biên dịch nữa. " hoàn toàn sai, vì bạn có thể thay đổi hợp đồng mà không thay đổi bất kỳ chữ ký phương thức nào. Nhưng thành thật mà nói, tôi nghĩ vấn đề ở đây là Vlad không sử dụng một cách nhất quán mà là kết hợp chúng - đó là nguyên nhân dẫn đến việc tuyên bố rằng bất kỳ thay đổi nào đối với hợp đồng X1 sẽ nhất thiết gây ra lỗi biên dịch mà không nhận thấy đó là sai .
Đánh dấu Amery

9

Lần lượt lấy câu hỏi của bạn:

kiểm tra đơn vị có giá trị gì

Chúng rẻ để viết và chạy và bạn nhận được phản hồi sớm. Nếu bạn phá vỡ X, bạn sẽ tìm ra ít nhiều ngay lập tức nếu bạn có bài kiểm tra tốt. Thậm chí đừng xem xét việc viết các bài kiểm tra tích hợp trừ khi đơn vị bạn đã kiểm tra tất cả các lớp của bạn (có, ngay cả trên cơ sở dữ liệu).

Có thực sự chỉ cho bạn biết rằng khi tất cả các bài kiểm tra vượt qua, bạn đã không đưa ra một thay đổi đột phá

Có những bài kiểm tra vượt qua thực sự có thể cho bạn biết rất ít. Bạn có thể không có đủ bài kiểm tra viết. Bạn có thể không kiểm tra đủ kịch bản. Bảo hiểm mã có thể giúp đỡ ở đây nhưng nó không phải là một viên đạn bạc. Bạn có thể có các bài kiểm tra luôn luôn vượt qua. Do đó màu đỏ là bước đầu tiên thường bị bỏ qua của màu đỏ, xanh lục, tái cấu trúc.

Và khi hành vi của một số lớp thay đổi (sẵn sàng hoặc không sẵn lòng), làm thế nào bạn có thể phát hiện (tốt nhất là theo cách tự động) tất cả các hậu quả

Thử nghiệm nhiều hơn - mặc dù các công cụ đang ngày càng tốt hơn. NHƯNG bạn nên xác định hành vi lớp trong một giao diện (xem bên dưới). NB sẽ luôn có một nơi để thử nghiệm thủ công trên đỉnh kim tự tháp thử nghiệm.

Chúng ta không nên tập trung nhiều hơn vào thử nghiệm tích hợp?

Bao giờ nhiều bài kiểm tra tích hợp cũng không phải là câu trả lời, chúng rất tốn kém để viết, chạy và duy trì. Tùy thuộc vào thiết lập bản dựng của bạn, trình quản lý bản dựng của bạn có thể loại trừ chúng bằng mọi cách khiến chúng phụ thuộc vào ghi nhớ của nhà phát triển (không bao giờ là điều tốt!).

Tôi đã thấy các nhà phát triển dành hàng giờ cố gắng khắc phục các thử nghiệm tích hợp bị hỏng mà họ đã tìm thấy trong năm phút nếu họ có các thử nghiệm đơn vị tốt. Không thực hiện được điều này, hãy thử chỉ chạy phần mềm - đó là tất cả những gì người dùng cuối của bạn sẽ quan tâm. Không có điểm nào có hàng triệu bài kiểm tra vượt qua nếu toàn bộ ngôi nhà thẻ rơi xuống khi người dùng chạy toàn bộ bộ.

Nếu bạn muốn chắc chắn rằng lớp A tiêu thụ lớp X theo cùng một cách, bạn nên sử dụng một giao diện chứ không phải là một sự lắng đọng. Sau đó, một thay đổi đột phá có nhiều khả năng được chọn vào thời gian biên dịch.


9

Đúng rồi.

Kiểm tra đơn vị ở đó để kiểm tra chức năng biệt lập của một đơn vị, kiểm tra trước mắt rằng nó hoạt động như dự định và không chứa lỗi ngu ngốc.

Kiểm tra đơn vị không có ở đó để kiểm tra rằng toàn bộ ứng dụng hoạt động.

Điều mà nhiều người quên là các bài kiểm tra đơn vị chỉ là phương tiện nhanh nhất và bẩn nhất để xác nhận mã của bạn. Khi bạn biết các thói quen nhỏ của mình hoạt động, bạn cũng phải chạy các bài kiểm tra Tích hợp. Tự kiểm tra đơn vị chỉ tốt hơn một chút so với không kiểm tra.

Lý do chúng tôi có các bài kiểm tra đơn vị là vì chúng được cho là rẻ. Nhanh chóng để tạo và chạy và bảo trì. Khi bạn bắt đầu biến chúng thành các bài kiểm tra tích hợp tối thiểu, bạn sẽ rơi vào một thế giới đau khổ. Bạn cũng có thể thực hiện kiểm tra Tích hợp đầy đủ và bỏ qua kiểm tra đơn vị hoàn toàn nếu bạn sẽ làm điều đó.

bây giờ, một số người nghĩ rằng một đơn vị không chỉ là một chức năng trong một lớp, mà là toàn bộ chính lớp đó (bao gồm cả bản thân tôi). Tuy nhiên, tất cả điều này làm tăng kích thước của đơn vị để bạn có thể cần kiểm tra tích hợp ít hơn, nhưng bạn vẫn cần nó. Vẫn không thể xác minh chương trình của bạn thực hiện những gì được cho là không có bộ kiểm thử tích hợp đầy đủ.

và sau đó, bạn sẽ vẫn cần chạy thử nghiệm tích hợp đầy đủ trên hệ thống trực tiếp (hoặc bán trực tiếp) để kiểm tra xem nó có hoạt động với các điều kiện khách hàng sử dụng không.


2

Các bài kiểm tra đơn vị không chứng minh tính đúng đắn của bất cứ điều gì. Điều này đúng cho tất cả các bài kiểm tra. Thông thường các bài kiểm tra đơn vị được kết hợp với thiết kế dựa trên hợp đồng (thiết kế theo hợp đồng là một cách khác để nói) và có thể là bằng chứng chính xác tự động, nếu tính chính xác cần phải được xác minh một cách thường xuyên.

Nếu bạn có hợp đồng thực sự, bao gồm các bất biến lớp, điều kiện tiên quyết và điều kiện đăng, có thể chứng minh tính đúng đắn theo thứ bậc, bằng cách dựa trên tính chính xác của các thành phần cấp cao hơn trên các hợp đồng của các thành phần cấp thấp hơn. Đây là khái niệm cơ bản đằng sau thiết kế bằng hợp đồng.


Các bài kiểm tra đơn vị không chứng minh tính đúng đắn của bất cứ điều gì . Không chắc chắn tôi hiểu điều này, kiểm tra đơn vị kiểm tra kết quả của họ chắc chắn? Hay bạn có nghĩa là một hành vi không thể được chứng minh là đúng vì điều này có thể bao gồm nhiều lớp?
Robbie Dee

7
@RobbieDee Tôi đoán, anh ta có nghĩa là khi bạn kiểm tra fac(5) == 120, bạn đã không chứng minh rằng điều fac()đó thực sự trả lại giai thừa cho lập luận của nó. Bạn chỉ chứng minh rằng fac()trả về giai thừa của năm khi bạn đi vào 5. Và thậm chí điều đó không chắc chắn, vì fac()có thể có thể quay trở lại 42vào những ngày đầu tiên sau khi nhật thực toàn phần ở Timbuktu ... Vấn đề ở đây là, bạn không thể chứng minh sự tuân thủ bằng cách kiểm tra từng đầu vào thử nghiệm, bạn sẽ cần kiểm tra tất cả các đầu vào có thể, và cũng chứng minh rằng bạn không quên bất kỳ (như đọc đồng hồ hệ thống).
cmaster

1
Các thử nghiệm @RobbieDee (bao gồm các thử nghiệm đơn vị) là một thay thế kém, thường là tốt nhất có sẵn, cho mục tiêu thực sự, một bằng chứng kiểm tra máy. Xem xét toàn bộ không gian trạng thái của các đơn vị được thử nghiệm, bao gồm không gian trạng thái của bất kỳ thành phần hoặc giả nào trong đó. Trừ khi bạn có một không gian trạng thái rất hạn chế, các bài kiểm tra không thể bao trùm không gian trạng thái đó. Bảo hiểm hoàn chỉnh sẽ là một bằng chứng, nhưng điều này chỉ khả dụng cho các không gian trạng thái nhỏ, ví dụ, kiểm tra một đối tượng duy nhất chứa một byte hoặc số nguyên 16 bit có thể thay đổi. Bằng chứng tự động có giá trị hơn nhiều.
Frank Hileman

1
@cmaster Bạn đã tóm tắt sự khác biệt giữa một bài kiểm tra và một bằng chứng rất tốt. Cảm ơn!
Frank Hileman

2

Tôi thấy các bài kiểm tra bị chế giễu rất hiếm khi hữu ích. Hầu hết thời gian, tôi kết thúc việc thực hiện lại hành vi mà lớp ban đầu đã có, hoàn toàn đánh bại mục đích chế giễu.

Một chiến lược tốt hơn là phân tách các mối quan tâm tốt (ví dụ: bạn có thể kiểm tra Phần A của ứng dụng của mình mà không cần đưa các phần B đến Z). Một kiến ​​trúc tốt như vậy thực sự giúp viết bài kiểm tra tốt.

Ngoài ra, tôi sẵn sàng chấp nhận các tác dụng phụ miễn là tôi có thể khôi phục chúng, ví dụ: nếu phương thức của tôi sửa đổi dữ liệu trong db, hãy để nó! Miễn là tôi có thể đưa db trở lại trạng thái trước đó, có hại gì không? Ngoài ra, có lợi ích mà thử nghiệm của tôi có thể kiểm tra nếu dữ liệu trông như mong đợi. DB trong bộ nhớ hoặc các phiên bản thử nghiệm cụ thể của dbs thực sự hữu ích ở đây (ví dụ: phiên bản thử nghiệm trong bộ nhớ RavenDB).

Cuối cùng, tôi thích chế giễu các ranh giới dịch vụ, ví dụ: không thực hiện cuộc gọi http đó đến dịch vụ b, nhưng hãy chặn nó và giới thiệu một cách thích hợp


1

Tôi ước mọi người ở cả hai trại sẽ hiểu rằng kiểm tra lớp và kiểm tra hành vi không phải là trực giao.

Kiểm tra lớp và kiểm tra đơn vị được sử dụng thay thế cho nhau và có lẽ chúng không nên. Một số bài kiểm tra đơn vị chỉ xảy ra để được thực hiện trong các lớp. Đó là tất cả. Kiểm tra đơn vị đã xảy ra trong nhiều thập kỷ trong các ngôn ngữ mà không có lớp học.

Đối với các hành vi kiểm thử, hoàn toàn có thể thực hiện việc này trong kiểm tra lớp bằng cách sử dụng cấu trúc GWT.

Hơn nữa, việc kiểm tra tự động của bạn có tiến hành dọc theo lớp hoặc hành vi hay không phụ thuộc vào mức độ ưu tiên của bạn. Một số người sẽ cần nhanh chóng tạo nguyên mẫu và lấy thứ gì đó ra khỏi cửa trong khi những người khác sẽ bị hạn chế bảo hiểm do kiểu nhà. Nhiều lý do. Cả hai đều là phương pháp hoàn toàn hợp lệ. Bạn trả tiền của bạn, bạn có sự lựa chọn của bạn.

Vậy, phải làm gì khi mã bị hỏng. Nếu nó đã được mã hóa thành một giao diện, thì chỉ cần thay đổi (cùng với bất kỳ thử nghiệm nào).

Tuy nhiên, giới thiệu một hành vi mới không cần phải thỏa hiệp hệ thống. Linux et al có đầy đủ các tính năng không dùng nữa. Và những thứ như constructor (và phương thức) có thể vui vẻ bị quá tải mà không buộc tất cả mã gọi thay đổi.

Trường hợp kiểm tra lớp chiến thắng là nơi bạn cần thực hiện thay đổi đối với một lớp chưa được thực hiện (do hạn chế về thời gian, độ phức tạp hoặc bất cứ điều gì). Thật dễ dàng hơn nhiều để bắt đầu với một lớp nếu nó có các bài kiểm tra toàn diện.


Nơi bạn có ngưng kết tôi sẽ phải viết thực hiện . Đây có phải là một calque từ một ngôn ngữ khác (tôi đoán tiếng Pháp) hoặc có một sự phân biệt quan trọng giữa sự lắng đọngthực hiện ?
Peter Taylor

0

Trừ khi giao diện cho X thay đổi, bạn không cần thay đổi kiểm tra đơn vị cho A vì không có gì liên quan đến A đã thay đổi. Nghe có vẻ như bạn thực sự đã viết một bài kiểm tra đơn vị của X và A cùng nhau, nhưng gọi đó là bài kiểm tra đơn vị của A:

Khi bạn viết bài kiểm tra đơn vị cho A, bạn giả định X. Nói cách khác, trong khi kiểm tra đơn vị A, bạn đặt (định nghĩa) hành vi của giả của X là X1.

Lý tưởng nhất là giả của X nên mô phỏng tất cả các hành vi có thể có của X, không chỉ là hành vi mà bạn mong đợi từ X. Vì vậy, bất kể bạn thực sự thực hiện điều gì trong X, A đều có khả năng xử lý nó. Vì vậy, không có thay đổi nào đối với X, ngoài việc thay đổi giao diện, sẽ có bất kỳ ảnh hưởng nào đến bài kiểm tra đơn vị cho A.

Ví dụ: Giả sử A là một thuật toán sắp xếp và A cung cấp dữ liệu được sắp xếp. Giả lập của X nên cung cấp giá trị trả về null, danh sách dữ liệu trống, một phần tử, nhiều phần tử đã được sắp xếp, nhiều phần tử chưa được sắp xếp, nhiều phần tử được sắp xếp ngược, liệt kê cùng một phần tử được lặp lại, giá trị null xen kẽ, một cách lố bịch số lượng lớn các yếu tố, và nó cũng nên ném một ngoại lệ.

Vì vậy, có lẽ ban đầu X trả về dữ liệu được sắp xếp vào thứ Hai và danh sách trống vào thứ Ba. Nhưng bây giờ khi X trả về dữ liệu chưa được sắp xếp vào thứ Hai và ném ngoại lệ vào thứ Ba, A không quan tâm - những kịch bản đó đã được đề cập trong bài kiểm tra đơn vị của A.


Điều gì xảy ra nếu X chỉ đổi tên chỉ mục trong mảng được trả về từ foobar thành foobarRandomNumber, làm thế nào tôi có thể tính được điều đó? Nếu bạn hiểu ý tôi, về cơ bản đây là vấn đề của tôi, tôi đã đổi tên một cột được trả lại từ secondName thành họ, một nhiệm vụ cổ điển, nhưng thử nghiệm của tôi sẽ không bao giờ biết, vì nó bị chế giễu. Tôi chỉ có một cảm giác kỳ lạ như thể nhiều người trong câu hỏi này chưa bao giờ thực sự thử điều gì như vậy, trước khi bình luận
FantomX1

Trình biên dịch sẽ phát hiện ra sự thay đổi này và cung cấp cho bạn một lỗi trình biên dịch. Nếu bạn đang sử dụng một cái gì đó như Javascript, thì tôi khuyên bạn nên chuyển sang Bản mô tả hoặc sử dụng trình biên dịch như Babel có thể phát hiện nội dung này.
Đĩa Moby

Điều gì sẽ xảy ra nếu tôi đang sử dụng các mảng trong PHP, hoặc trong Java hoặc trong Javascript, nếu bạn thay đổi một chỉ mục của mảng hoặc loại bỏ nó, không phải các trình biên dịch ngôn ngữ đó sẽ cho bạn biết về nó, chỉ mục có thể được lồng vào số thứ 36 mức lồng nhau của mảng, do đó tôi nghĩ trình biên dịch không phải là giải pháp cho việc này.
FantomX1

-2

Bạn phải xem xét các bài kiểm tra khác nhau.

Bản thân các bài kiểm tra đơn vị sẽ chỉ kiểm tra X. Chúng có mặt để ngăn bạn thay đổi hành vi của X nhưng không bảo mật toàn bộ hệ thống. Họ đảm bảo bạn có thể cấu trúc lại lớp của mình mà không đưa ra thay đổi trong hành vi. Và nếu bạn phá vỡ X, bạn đã phá vỡ nó ...

A thực sự nên giả lập X cho các bài kiểm tra đơn vị của nó và bài kiểm tra với Mock sẽ tiếp tục vượt qua ngay cả khi bạn thay đổi nó.

Nhưng có nhiều hơn một cấp độ thử nghiệm! Ngoài ra còn có các bài kiểm tra tích hợp. Các thử nghiệm này là để xác nhận sự tương tác giữa các lớp. Các xét nghiệm này thường có giá cao hơn vì chúng không sử dụng giả cho mọi thứ. Ví dụ, một bài kiểm tra tích hợp thực sự có thể ghi một bản ghi vào cơ sở dữ liệu và một bài kiểm tra đơn vị không nên có sự phụ thuộc bên ngoài.

Ngoài ra, nếu X cần có một hành vi mới, sẽ tốt hơn nếu cung cấp một phương thức mới sẽ cung cấp kết quả mong muố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.