Có quá nhiều xác nhận mã mùi?


19

Tôi thực sự yêu thích thử nghiệm đơn vị và TDD - Tôi đang thử nghiệm bị nhiễm bệnh.

Tuy nhiên, kiểm tra đơn vị thường được sử dụng cho các phương pháp công cộng. Đôi khi, mặc dù tôi cũng phải kiểm tra một số giả định - các xác nhận trong các phương thức riêng tư, bởi vì một số trong số chúng là "nguy hiểm" và tái cấu trúc không thể giúp gì thêm. (Tôi biết, các khung kiểm tra cho phép thử nghiệm các phương thức riêng tư).

Vì vậy, nó trở thành một thói quen của tôi rằng dòng đầu tiên và dòng cuối cùng của một phương thức riêng tư đều là các xác nhận.

Tuy nhiên, tôi nhận thấy rằng tôi có xu hướng sử dụng các xác nhận trong các phương thức công khai (cũng như riêng tư) chỉ "để chắc chắn". Đây có thể là "trùng lặp thử nghiệm" vì các giả định phương thức công khai được kiểm tra từ bên ngoài bởi khung thử nghiệm đơn vị không?

Ai đó có thể nghĩ về quá nhiều khẳng định là một mùi mã?


1
Là những khẳng định trên hoặc tắt trong phát hành?
jk.

Tôi làm việc chủ yếu với Java nơi các xác nhận phải được kích hoạt thủ công.
Florents Tselai

Chỉ cần tìm thấy "Các xác nhận tăng năng suất bằng cách theo dõi các lỗi" lập trình
viên.stackexchange.com/a/16317/32342

Làm thế nào để bạn xác định "quá nhiều"?
haylem

@haylem Có các xác nhận "quá nhiều" nếu một lập trình viên khác đọc mã và nói "Tôi mệt mỏi với các xác nhận này".
Florents Tselai

Câu trả lời:


26

Những xác nhận đó thực sự hữu ích để kiểm tra các giả định của bạn, nhưng chúng cũng phục vụ một mục đích thực sự quan trọng khác: tài liệu. Bất kỳ người đọc phương pháp nào cũng có thể đọc các xác nhận để nhanh chóng xác định các điều kiện trước và sau mà không cần phải xem bộ kiểm tra. Vì lý do này, tôi khuyên bạn nên giữ những khẳng định đó vì lý do tài liệu, thay vì lý do kiểm tra. Về mặt kỹ thuật, bạn đang sao chép các xác nhận, nhưng chúng phục vụ hai mục đích khác nhau và rất hữu ích trong cả hai.

Giữ chúng như những khẳng định tốt hơn là sử dụng bình luận, bởi vì chúng chủ động kiểm tra các giả định bất cứ khi nào chúng được chạy.


2
Điểm rất tốt!
Florents Tselai

1
Các xác nhận là tài liệu, nhưng điều đó không làm cho việc sao chép chúng hợp pháp. Ngược lại, nó thậm chí còn làm dấy lên nghi ngờ về chất lượng của các bài kiểm tra nếu có vẻ như các xác nhận tương tự là cần thiết hơn một lần.
Yam Marcovic

1
@YamMarcovic Tôi nghĩ điều này có thể chấp nhận được vì hai đoạn mã "trùng lặp" phục vụ hai mục đích khác nhau và khác biệt. Tôi nghĩ rằng rất hữu ích khi có chúng ở cả hai địa điểm, mặc dù có sự trùng lặp. Có các xác nhận trong phương thức là vô giá đối với tài liệu và rõ ràng chúng là bắt buộc để thử nghiệm.
Oleksi

2
Các xác nhận trong mã đối với tôi là bổ sung cho các xác nhận thử nghiệm đơn vị. Bạn sẽ không có phạm vi kiểm tra 100% và các xác nhận trong mã sẽ giúp bạn thu hẹp các bài kiểm tra đơn vị thất bại nhanh hơn.
sebastiangeiger

15

Có vẻ như bạn đang cố gắng thực hiện Thiết kế theo hợp đồng bằng tay.

Làm DbC là một ý tưởng tốt, nhưng ít nhất bạn nên xem xét chuyển sang ngôn ngữ hỗ trợ ngôn ngữ đó (chẳng hạn như Eiffel ) hoặc ít nhất sử dụng khung hợp đồng cho nền tảng của bạn (ví dụ: Hợp đồng mã Microsoft cho .NETlà khá đẹp, được cho là khung hợp đồng tinh vi nhất ngoài kia, thậm chí còn mạnh hơn cả Eiffel). Bằng cách đó, bạn có thể tận dụng tốt hơn sức mạnh của hợp đồng. Ví dụ: bằng cách sử dụng khung hiện có, bạn có thể hiển thị các hợp đồng trong tài liệu của mình hoặc IDE (ví dụ: Hợp đồng mã cho .NET được hiển thị trong IntelliSense và, nếu bạn có VS Ultimate, thậm chí có thể được kiểm tra tĩnh bởi trình cung cấp định lý tự động trong thời gian biên dịch bạn gõ, tương tự, nhiều khung hợp đồng Java có các tài liệu JavaDoc sẽ tự động trích xuất các hợp đồng vào tài liệu API JavaDoc của bạn).

Và ngay cả khi nó chỉ ra rằng trong tình huống của bạn không có cách nào khác để thực hiện thủ công, thì bây giờ bạn ít nhất cũng biết nó được gọi là gì và có thể đọc về nó.

Vì vậy, tóm lại: nếu bạn thực sự đang làm DbC, ngay cả khi bạn không biết điều đó, thì những khẳng định đó là hoàn toàn tốt.


4

Bất cứ khi nào bạn không có toàn quyền kiểm soát các tham số đầu vào của mình, bạn nên kiểm tra trước các lỗi đơn giản. Thất bại trên null chẳng hạn.

Đây không phải là bản sao của các thử nghiệm của bạn, vì chúng nên kiểm tra rằng mã không phù hợp với các tham số đầu vào xấu, và sau đó ghi lại điều đó .

Tôi không nghĩ bạn nên khẳng định các tham số trả về (trừ khi bạn rõ ràng có một bất biến mà bạn muốn người đọc hiểu). Đây cũng là công việc của những người không lành mạnh.

Cá nhân tôi không thích assertcâu lệnh trong Java, vì chúng có thể bị tắt và sau đó nó là một bảo mật sai.


1
+1 Vì "Tôi không thích câu lệnh khẳng định trong Java, vì chúng có thể bị tắt và sau đó nó là một bảo mật sai."
Florents Tselai

3

Tôi nghĩ rằng việc sử dụng các xác nhận trong các phương thức công cộng thậm chí còn quan trọng hơn, vì ở đó bạn không kiểm soát các đầu vào và có thể có nhiều khả năng bị giả định bị phá vỡ.

Kiểm tra các điều kiện đầu vào nên được thực hiện trong tất cả các phương pháp công cộng và được bảo vệ. Nếu các đầu vào được truyền trực tiếp đến một phương thức riêng tư, thì việc kiểm tra các đầu vào của nó có thể là dự phòng.

Kiểm tra các điều kiện đầu ra (ví dụ trạng thái đối tượng hoặc giá trị trả về đó! = Null) nên được thực hiện trong các phương thức bên trong (ví dụ: phương thức riêng). Nếu các đầu ra được truyền trực tiếp từ phương thức riêng sang đầu ra của phương thức công khai mà không tính toán bổ sung hoặc thay đổi trạng thái bên trong, thì việc kiểm tra các điều kiện đầu ra của phương thức công khai có thể là dự phòng.

Tôi đồng ý với Oleksi, tuy nhiên, sự dư thừa có thể làm tăng khả năng đọc và nó cũng có thể tăng khả năng bảo trì (nếu việc chuyển nhượng trực tiếp hoặc trả lại không còn là vấn đề trong tương lai).


4
Nếu một điều kiện lỗi hoặc điều kiện đối số không hợp lệ có thể do người dùng (người gọi) của giao diện công cộng gây ra, thì điều này cần được cung cấp đầy đủ cách xử lý xử lý lỗi thích hợp. Điều này có nghĩa là định dạng một thông báo lỗi có ý nghĩa đối với người dùng cuối, kèm theo mã lỗi, ghi nhật ký và cố gắng khôi phục dữ liệu hoặc khôi phục về trạng thái lành mạnh. Thay thế xử lý lỗi thích hợp với các xác nhận sẽ làm cho mã kém mạnh mẽ hơn và khó khắc phục sự cố hơn.
rwong

Các xác nhận có thể (và trong nhiều trường hợp nên) bao gồm ghi nhật ký và ném ngoại lệ (hoặc mã lỗi trong C--).
Daniel Varod

3

Thật khó để không biết ngôn ngữ về vấn đề này, vì các chi tiết về cách xác nhận và xử lý lỗi / xử lý ngoại lệ 'đúng' được thực hiện có liên quan đến câu trả lời. Đây là 0,02 đô la của tôi, dựa trên kiến ​​thức về Java & C ++ của tôi.

Các xác nhận trong các phương thức riêng tư là một điều tốt, giả sử bạn không quá nhiệt tình và đặt chúng ở mọi nơi . Nếu bạn đang đặt chúng vào các phương thức thực sự đơn giản hoặc liên tục kiểm tra những thứ như các trường không thay đổi, thì bạn sẽ làm lộn xộn mã không cần thiết.

Khẳng định trong các phương pháp công cộng thường được tránh tốt nhất. Bạn vẫn nên làm những việc như kiểm tra xem hợp đồng phương thức không bị vi phạm, nhưng nếu đúng thì bạn nên đưa ra các ngoại lệ được gõ phù hợp với các thông điệp có ý nghĩa, hoàn nguyên trạng thái có thể, v.v. (cái mà @rwong gọi là "đầy đủ xử lý lỗi thích hợp ").

Nói chung, bạn chỉ nên sử dụng khẳng định để giúp bạn phát triển / gỡ lỗi. Bạn không thể cho rằng bất cứ ai sử dụng API của bạn thậm chí sẽ kích hoạt các xác nhận khi họ sử dụng mã của bạn. Mặc dù chúng có một số ứng dụng trong việc giúp ghi lại mã, nhưng thường có những cách tốt hơn để ghi lại những điều tương tự (ví dụ: tài liệu phương thức, ngoại lệ).


2

Thêm vào danh sách (hầu hết) các câu trả lời đặc biệt, một lý do khác cho rất nhiều khẳng định và trùng lặp, là bạn không biết làm thế nào, khi nào hoặc bởi ai mà lớp sẽ được sửa đổi trong suốt thời gian tồn tại. Nếu bạn đang viết mã vứt đi sẽ chết trong một năm, không phải là một mối quan tâm. Nếu bạn đang viết mã sẽ được sử dụng trong hơn 20 năm, nó sẽ trông khá khác biệt - và một giả định bạn đưa ra có thể không còn hiệu lực. Anh chàng thực hiện thay đổi đó sẽ cảm ơn bạn vì những lời khẳng định.

Ngoài ra, không phải tất cả các lập trình viên đều hoàn hảo - một lần nữa, các khẳng định có nghĩa là một trong những "cú trượt" đó sẽ không lan truyền quá xa.

Đừng đánh giá thấp hiệu quả của những khẳng định này (và các kiểm tra khác về các giả định) sẽ có trong việc giảm chi phí bảo trì.


0

Có các xác nhận trùng lặp không phải là sai mỗi se, nhưng có các xác nhận "chỉ để đảm bảo" không phải là tốt nhất. Nó thực sự nắm bắt chính xác những gì mỗi bài kiểm tra đang cố gắng thực hiện. Chỉ khẳng định những gì là hoàn toàn cần thiết. Nếu một thử nghiệm sử dụng Moq để xác minh một phương thức được gọi, thì thực sự không có vấn đề gì xảy ra sau khi phương thức đó được gọi, thử nghiệm chỉ liên quan đến việc đảm bảo phương thức được gọi.

Nếu mọi bài kiểm tra đơn vị có cùng một tập hợp các xác nhận, ngoại trừ một hoặc hai, thì khi bạn cấu trúc lại một chút, tất cả các bài kiểm tra có thể thất bại vì cùng một lý do, thay vì cho bạn thấy tác động thực sự của bộ tái cấu trúc. Bạn có thể rơi vào tình huống bạn chạy tất cả các bài kiểm tra, tất cả đều thất bại vì mọi bài kiểm tra đều có cùng một khẳng định, bạn sửa lỗi đó, chạy lại các bài kiểm tra, chúng thất bại vì một lý do khác, bạn sửa lỗi đó. Lặp lại cho đến khi hoàn thành.

Cũng xem xét việc duy trì dự án thử nghiệm của bạn. Điều gì xảy ra khi bạn thêm một tham số mới, hoặc đầu ra được điều chỉnh từng chút một, bạn sẽ phải quay lại qua một loạt các thử nghiệm và thay đổi một xác nhận hoặc thêm một xác nhận? Và, tùy thuộc vào mã của bạn, cuối cùng bạn có thể phải thiết lập nhiều hơn chỉ để đảm bảo tất cả các xác nhận đều vượt qua.

Tôi có thể hiểu được sức hấp dẫn của việc muốn bao gồm các xác nhận trùng lặp trong bài kiểm tra đơn vị, nhưng nó thực sự là quá mức cần thiết. Tôi đã đi xuống cùng một con đường với dự án thử nghiệm đầu tiên của tôi. Tôi đã đi xa nó bởi vì sự bảo trì một mình đã khiến tôi phát điên.


0

Tuy nhiên, thử nghiệm đơn vị được sử dụng cho các phương pháp công cộng.

Nếu khung thử nghiệm của bạn cho phép người truy cập, thì phương pháp thử nghiệm đơn vị cũng là một ý tưởng tốt (IMO).

Ai đó có thể nghĩ về quá nhiều khẳng định là một mùi mã?

Tôi làm. Các xác nhận là ổn, nhưng mục tiêu đầu tiên của bạn là làm cho nó để kịch bản thậm chí không thể thực hiện được ; không chỉ là nó không xảy ra


-2

Đó là thực tế xấu.

Bạn không nên thử phương pháp công khai / riêng tư. Bạn nên kiểm tra toàn bộ lớp học. Chỉ cần chắc chắn rằng bạn có bảo hiểm tốt.

Nếu bạn đi theo cách riêng (nguyên thủy) để kiểm tra riêng từng phương thức như một quy tắc chung, bạn sẽ thấy rất khó để cấu trúc lại lớp của mình trong tương lai. Và đó là một trong những điều tốt nhất TDD cho phép bạn làm.

Bên cạnh đó, nó là sự trùng lặp. Hơn nữa, nó gợi ý rằng người viết mã không thực sự biết anh ta đang làm gì. Và điều buồn cười là, bạn làm .

Một số người đối xử với các xét nghiệm của họ với sự chăm sóc ít hơn so với mã sản xuất của họ. Họ không nên. Nếu bất cứ điều gì, kinh nghiệm của tôi đề nghị thậm chí xử lý các xét nghiệm cẩn thận hơn. Họ đáng giá nó.


-1 Đơn vị kiểm tra toàn bộ một lớp có thể nguy hiểm vì bạn kết thúc kiểm tra nhiều hơn một điều cho mỗi bài kiểm tra. Điều này làm cho các bài kiểm tra thực sự giòn. Bạn nên kiểm tra một phần hành vi cùng một lúc, thường tương ứng với kiểm tra chỉ một phương pháp cho mỗi kiểm tra.
Oleksi

Cũng liên quan đến "nó gợi ý rằng người viết mã không thực sự biết anh ta đang làm gì [...] bạn làm gì." Các nhà phát triển trong tương lai có thể không rõ ràng về những gì một phương pháp cụ thể làm. Trong trường hợp này, có các điều kiện trước và sau dưới dạng xác nhận có thể là vô giá trong việc hiểu một đoạn mã.
Oleksi

2
@Oleksi Thử nghiệm tốt là về các kịch bản sử dụng hợp lệ, không phải về việc xác nhận mọi chi tiết không liên quan nhỏ nhất. Các xác nhận dư thừa thực sự là một mùi mã bởi vì mục đích mơ hồ, và chỉ là một ví dụ tồi tệ khác của lập trình phòng thủ.
Yam Marcovic
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.