Có cần phải giữ các bài kiểm tra cho các chức năng đơn giản (khép kín) không?


36

Xem xét điều này:

public function polynominal($a, $b, $c, $d)
{
    return  $a * pow($x, 3) + $b * pow($x, 2) + $c * $x + $d;
}

Giả sử bạn viết các bài kiểm tra khác nhau cho chức năng trên và chứng minh cho bản thân và những người khác rằng "nó hoạt động".

Tại sao không loại bỏ những bài kiểm tra đó, và sống hạnh phúc mãi mãi về sau? Quan điểm của tôi là một số chức năng không cần phải được kiểm tra liên tục sau khi chúng đã được chứng minh là có hiệu quả. Tôi đang tìm kiếm các điểm phản đối trạng thái, vâng, các chức năng này vẫn cần được kiểm tra, bởi vì: ... Hoặc có, những điều này không cần phải được kiểm tra ...


32
Điều đó không đúng với mọi chức năng trừ khi bạn thay đổi mã của mình, nếu nó hoạt động vào ngày hôm qua, nó cũng sẽ hoạt động vào ngày mai? Vấn đề là phần mềm được thay đổi.
5gon12eder

3
Bởi vì không ai sẽ viết override_function('pow', '$a,$b', 'return $a * $b;');theo ý mình ... hoặc cố gắng viết lại để xử lý các số phức.

8
Vì vậy, ... ừm ... rằng "được chứng minh là mã không có lỗi" ... nó có một lỗi .

Đối với các chức năng nhỏ như thế này, bạn có thể muốn xem xét thử nghiệm dựa trên thuộc tính. Kiểm tra dựa trên thuộc tính tự động tạo ra các testcase và kiểm tra các bất biến được xác định trước. Họ cung cấp tài liệu thông qua các bất biến, điều này làm cho chúng hữu ích để giữ xung quanh. Đối với các chức năng đơn giản như thế này, chúng là hoàn hảo.
Martijn

6
Ngoài ra, chức năng đó là một ứng cử viên tuyệt vời để thay đổi hình thức của Horner (($a*$x + $b)*$x + $c)*$x + $drất dễ bị sai, nhưng thường nhanh hơn đáng kể. Chỉ vì bạn nghĩ rằng nó sẽ không thay đổi không có nghĩa là nó sẽ không thay đổi.
Michael Anderson

Câu trả lời:


78

Kiểm tra hồi quy

Đó là tất cả về thử nghiệm hồi quy .

Hãy tưởng tượng nhà phát triển tiếp theo nhìn vào phương pháp của bạn và nhận thấy rằng bạn đang sử dụng các con số ma thuật. Anh ta được cho biết rằng những con số ma thuật là xấu xa, vì vậy anh ta tạo ra hai hằng số, một cho số hai, một cho số ba khác, không có gì sai khi thực hiện thay đổi này; không giống như anh ta đang sửa đổi cách thực hiện đã đúng của bạn.

Bị phân tâm, anh ta đảo ngược hai hằng số.

Anh ta cam kết mã, và mọi thứ dường như hoạt động tốt, bởi vì không có kiểm tra hồi quy nào chạy sau mỗi lần xác nhận.

Một ngày (có thể là vài tuần sau), một cái gì đó phá vỡ ở nơi khác. Và ở nơi khác, tôi có nghĩa là ở vị trí hoàn toàn trái ngược của cơ sở mã, dường như không liên quan gì đến polynominalchức năng. Giờ sửa lỗi đau đớn dẫn đến thủ phạm. Trong thời gian này, ứng dụng tiếp tục thất bại trong sản xuất, gây ra rất nhiều vấn đề cho khách hàng của bạn.

Giữ các bài kiểm tra ban đầu bạn viết có thể ngăn chặn nỗi đau như vậy. Nhà phát triển bị phân tâm sẽ cam kết mã, và gần như ngay lập tức thấy rằng anh ta đã phá vỡ một cái gì đó; mã như vậy thậm chí sẽ không đạt được sản xuất. Các bài kiểm tra đơn vị cũng sẽ rất chính xác về vị trí của lỗi . Giải quyết nó sẽ không khó.

Một tác dụng phụ...

Trên thực tế, hầu hết tái cấu trúc chủ yếu dựa trên thử nghiệm hồi quy. Thực hiện một thay đổi nhỏ. Kiểm tra. Nếu nó vượt qua, mọi thứ đều ổn.

Tác dụng phụ là nếu bạn không có các bài kiểm tra, thì thực tế bất kỳ việc tái cấu trúc nào cũng trở thành nguy cơ rất lớn trong việc phá mã. Vì có nhiều trường hợp, thật khó để giải thích với ban quản lý rằng việc tái cấu trúc nên được thực hiện, sẽ còn khó hơn nữa sau khi các nỗ lực tái cấu trúc trước đó của bạn đưa ra nhiều lỗi.

Bằng cách có một bộ kiểm tra hoàn chỉnh, bạn đang khuyến khích tái cấu trúc, và do đó, mã sạch hơn, tốt hơn. Không có rủi ro, nó trở nên rất hấp dẫn để tái cấu trúc nhiều hơn, trên cơ sở thường xuyên.

Thay đổi yêu cầu

Một khía cạnh thiết yếu khác là yêu cầu thay đổi. Bạn có thể được yêu cầu xử lý các số phức và đột nhiên, bạn cần tìm kiếm nhật ký kiểm soát phiên bản của mình để tìm các thử nghiệm trước đó, khôi phục chúng và bắt đầu thêm các thử nghiệm mới.

Tại sao tất cả những rắc rối này? Tại sao loại bỏ các bài kiểm tra để thêm chúng sau này? Bạn có thể đã giữ chúng ở nơi đầu tiên.


Lưu ý Pedantic: không có gì là không có rủi ro. ;)
jpmc26

2
Hồi quy là lý do số một để kiểm tra đối với tôi - ngay cả khi mã của bạn rõ ràng về trách nhiệm và chỉ sử dụng bất cứ điều gì được truyền cho nó (ví dụ như không có toàn cầu), thì quá dễ dàng để phá vỡ một cái gì đó một cách tình cờ. Các thử nghiệm không hoàn hảo, nhưng chúng vẫn rất tuyệt (và hầu như luôn ngăn chặn cùng một lỗi xuất hiện trở lại, điều mà hầu hết khách hàng đều không hài lòng). Nếu thử nghiệm của bạn hoạt động, không có chi phí bảo trì. Nếu họ ngừng hoạt động, bạn có thể tìm thấy một lỗi. Tôi đang làm việc trên một ứng dụng cũ với hàng ngàn toàn cầu - không có thử nghiệm, tôi sẽ không dám thực hiện nhiều thay đổi cần thiết.
Luaan

Một lưu ý khác về phạm vi: Một số số "ma thuật" thực sự ổn, và thay thế chúng bằng hằng số là một ý tưởng tồi.
Ded repeatator

3
@Ded repeatator chúng tôi biết điều đó, nhưng rất nhiều lập trình viên mới được đào tạo đại học đặc biệt rất nhiệt tình về những câu thần chú mù quáng. Và "số ma thuật là xấu xa" là một trong số đó. Một cách khác là "bất cứ điều gì được sử dụng nhiều lần phải được tái cấu trúc thành một phương thức" dẫn đến các trường hợp cực đoan với vô số phương thức có chứa nhưng một câu lệnh duy nhất (và sau đó họ tự hỏi tại sao hiệu suất đột nhiên giảm xuống, họ không bao giờ biết về các cuộc gọi).
jwenting

@jwenting: Chỉ cần thêm ghi chú đó vì MainMa đã viết "không có gì sai khi thực hiện thay đổi này".
Ded repeatator

45

Bởi vì không có gì đơn giản đến mức không thể có lỗi.

Mã của bạn, trong khi trên mặt của nó có vẻ là không có lỗi. Thực tế nó là một biểu diễn lập trình đơn giản của hàm đa thức.

Ngoại trừ nó có một lỗi ...

public function polynominal($a, $b, $c, $d)
{
    return  $a * pow($x, 3) + $b * pow($x, 2) + $c * $x + $d;
}

$xkhông được định nghĩa là đầu vào cho mã của bạn và tùy thuộc vào ngôn ngữ hoặc thời gian chạy hoặc phạm vi, chức năng của bạn có thể không hoạt động, có thể gây ra kết quả không hợp lệ hoặc có thể làm hỏng tàu vũ trụ .


Phụ lục:

Mặc dù bây giờ bạn có thể xem xét lỗi mã của mình miễn phí, nhưng đó là trường hợp khó nói. Mặc dù có thể lập luận rằng việc viết một bài kiểm tra cho một đoạn mã tầm thường như vậy là không đáng, nhưng đã viết bài kiểm tra thì công việc được thực hiện và xóa nó là xóa một người bảo vệ an toàn hữu hình.

Lưu ý thêm là các dịch vụ bảo hiểm mã (như coveralls.io) cung cấp một dấu hiệu tốt về phạm vi bảo hiểm mà bộ thử nghiệm cung cấp. Bằng cách bao gồm mọi dòng mã, bạn đưa ra một số liệu hợp lý về số lượng (nếu không phải là chất lượng) của thử nghiệm mà bạn thực hiện. Kết hợp với rất nhiều thử nghiệm nhỏ, các dịch vụ này ít nhất cho bạn biết nơi không tìm lỗi khi xảy ra.

Cuối cùng, nếu bạn đã có một bài kiểm tra viết, hãy giữ nó . Bởi vì không gian hoặc thời gian tiết kiệm từ việc xóa nó có thể sẽ ít hơn nhiều so với khoản nợ kỹ thuật sau này nếu có lỗi phát sinh.


Có một giải pháp thay thế: chuyển sang ngôn ngữ không yếu không năng động. Các bài kiểm tra đơn vị thường là một cách giải quyết để xác minh thời gian biên dịch không đủ mạnh và một số ngôn ngữ rất tốt trong en.wikipedia.org/wiki/Agda_(programming_lingu)
Den

21

Vâng. Nếu chúng ta có thể nói với độ tin cậy 100%, chắc chắn: chức năng này sẽ không bao giờ được chỉnh sửa và sẽ không bao giờ chạy trong bối cảnh có thể khiến nó bị lỗi - nếu chúng ta có thể nói điều đó, chúng ta có thể bỏ các bài kiểm tra và tiết kiệm vài mili giây mỗi giây Xây dựng CI.

Nhưng chúng ta không thể. Hoặc, chúng ta không thể có nhiều chức năng. Và thật đơn giản để có quy tắc chạy tất cả các bài kiểm tra mọi lúc hơn là nỗ lực xác định chính xác ngưỡng tin cậy mà chúng tôi hài lòng và chính xác mức độ tin cậy của chúng tôi đối với bất kỳ chức năng nhất định nào.

Và thời gian xử lý là rẻ. Những mili giây đó được lưu, thậm chí nhân lên nhiều lần, không cộng lại gần như đủ để biện minh cho việc dành thời gian với mọi chức năng để hỏi: chúng ta có đủ tự tin rằng chúng ta không cần phải kiểm tra lại không?


Tôi nghĩ rằng đó là một điểm rất tốt bạn đang đưa lên đây. Tôi đã có thể thấy hai anh chàng dành hàng giờ để tranh luận về việc giữ các bài kiểm tra cho một số chức năng nhỏ.
Kapol

@Kapol: không phải là một cuộc tranh luận, một cuộc họp để xác định cái nào có thể đi và cái nào có thể ở lại, và tiêu chí nào nên được sử dụng để quyết định, cũng như nơi để ghi lại các tiêu chí và ai ký vào quyết định cuối cùng ...
jmoreno

12

Tất cả mọi thứ nói trong các câu trả lời khác là chính xác, nhưng tôi sẽ thêm một câu nữa.

Tài liệu

Các thử nghiệm đơn vị, nếu được viết tốt, có thể giải thích cho nhà phát triển chính xác chức năng làm gì, kỳ vọng đầu vào / đầu ra của nó là gì và quan trọng hơn là hành vi nào có thể được mong đợi đối với nó.

Nó có thể làm cho việc phát hiện ra một lỗi dễ dàng hơn và sự nhầm lẫn thấp hơn.

Không phải ai cũng nhớ đa thức, hình học hay thậm chí đại số :) Nhưng một bài kiểm tra đơn vị tốt được kiểm tra trong kiểm soát phiên bản sẽ ghi nhớ cho tôi.

Để biết ví dụ về mức độ hữu ích của tài liệu này, hãy xem phần giới thiệu của Jasmine: http://jasmine.github.io/edge/int sinhtion.html Cho nó vài giây để tải, sau đó cuộn xuống phía dưới. Bạn sẽ thấy toàn bộ API Jasmine được ghi lại dưới dạng đầu ra thử nghiệm đơn vị.

[Cập nhật dựa trên phản hồi từ @Warbo] Các thử nghiệm được đảm bảo cập nhật cũng như nếu không, chúng sẽ thất bại, thường sẽ gây ra lỗi xây dựng nếu CI được sử dụng. Tài liệu bên ngoài thay đổi độc lập với mã, và do đó không nhất thiết phải cập nhật.


1
Có một lợi thế lớn khi sử dụng các bài kiểm tra dưới dạng (một phần) tài liệu mà bạn để lại ẩn: chúng tự động được kiểm tra. Các hình thức tài liệu khác, ví dụ. nhận xét giải thích hoặc đoạn mã trên trang Web, có thể bị lỗi thời khi mã phát triển. Các bài kiểm tra đơn vị sẽ gây ra lỗi nếu chúng không còn chính xác. Trang hoa nhài đó là một ví dụ cực đoan về điều này.
Warbo

Tôi muốn thêm rằng một số ngôn ngữ, như D và Rust, tích hợp việc tạo tài liệu của họ với thử nghiệm đơn vị của họ, để bạn có thể có cùng một đoạn mã được biên dịch thành một bài kiểm tra đơn vị và được chèn vào tài liệu HTML
Idan Arye

2

Kiểm tra thực tế

Tôi đã ở trong những môi trường đầy thách thức trong đó việc kiểm tra là "lãng phí thời gian" trong quá trình lập ngân sách và lịch trình, và sau đó là "một phần cơ bản của đảm bảo chất lượng" một khi khách hàng xử lý lỗi, vì vậy ý ​​kiến ​​của tôi trôi chảy hơn những người khác.

Bạn có một ngân sách. Công việc của bạn là có được sản phẩm tốt nhất có thể trong ngân sách đó, với bất kỳ định nghĩa nào về "tốt nhất" bạn có thể cạo cùng nhau (đó không phải là một từ dễ định nghĩa). Kết thúc câu chuyện.

Kiểm tra là một công cụ trong kho của bạn. Bạn nên sử dụng nó, bởi vì nó là một công cụ tốt , với lịch sử lâu dài tiết kiệm hàng triệu, hoặc thậm chí hàng tỷ đô la. Nếu có cơ hội, bạn nên thêm các bài kiểm tra cho các chức năng đơn giản này. Nó có thể cứu làn da của bạn một ngày nào đó.

Nhưng trong thế giới thực, với những hạn chế về ngân sách và lịch trình, điều đó có thể không xảy ra. Đừng biến mình thành nô lệ cho thủ tục. Các chức năng kiểm tra là tốt, nhưng tại một số điểm, giờ làm việc của bạn có thể được dành tốt hơn để viết tài liệu dành cho nhà phát triển bằng từ ngữ, thay vì mã, vì vậy nhà phát triển tiếp theo không cần kiểm tra nhiều. Hoặc tốt hơn là nên tái cấu trúc cơ sở mã để bạn không phải duy trì khó khăn như một con thú. Hoặc có lẽ thời gian đó là tốt hơn để nói chuyện với sếp của bạn về ngân sách và lịch trình để anh ấy hoặc cô ấy hiểu rõ hơn những gì họ đang đấu thầu khi vòng tài chính tiếp theo đi xuống.

Phát triển phần mềm là một sự cân bằng. Luôn tính chi phí cơ hội của bất cứ điều gì bạn đang làm để đảm bảo không có cách nào tốt hơn để dành thời gian của bạn.


4
Trong trường hợp này, đã có một bài kiểm tra, vì vậy câu hỏi không phải là viết chúng, mà là có nên cam kết và chạy chúng với mỗi bản dựng hoặc phát hành hay bất kỳ lịch trình nào có để chạy tất cả các bài kiểm tra.
Paŭlo Ebermann

0

Có, giữ các bài kiểm tra, giữ cho chúng chạy và giữ cho chúng đi qua.

Các bài kiểm tra đơn vị có mặt để bảo vệ bạn (và những người khác) khỏi chính bạn (và chính họ).

Tại sao giữ các bài kiểm tra là một ý tưởng tốt;

  • Xác thực chức năng của các yêu cầu trước khi đối mặt với các yêu cầu mới và chức năng bổ sung
  • Xác minh rằng các bài tập tái cấu trúc là chính xác
  • Tài liệu nội bộ - đây là cách mã dự kiến ​​sẽ được sử dụng
  • Kiểm tra hồi quy, mọi thứ thay đổi
    • Các thay đổi có phá vỡ mã cũ không?
    • Các thay đổi có yêu cầu thay đổi thêm hoặc cập nhật cho các chức năng hoặc mã hiện tại không?
  • Cho rằng các bài kiểm tra đã được viết, giữ chúng; đó là thời gian và tiền bạc đã bỏ ra sẽ giảm chi phí bảo trì xuống dòng

2
Điều này dường như không cung cấp bất cứ điều gì đáng kể so với các câu trả lời khác đã được cung cấp.

1
Có một vấn đề đăng nó trước đó, nhưng nhìn lại, đó là một bản tóm tắt tốt đẹp. Tôi sẽ xóa nó.
Niall

-1

Tài liệu dành cho nhà phát triển

  • Làm thế nào để tôi (với tư cách là nhà phát triển khác) biết rằng điều này đã được thử nghiệm?
  • Nếu tôi muốn sửa một lỗi trong hàm tự chứa , làm sao tôi biết rằng tôi không giới thiệu một lỗi mà bạn đã xem xét?
  • Chỉ số phức tạp: # các bài kiểm tra có thể là thước đo tốt về mức độ phức tạp của một thứ gì đó. Điều này có thể chỉ ra rằng bạn không nên chạm vào nó bởi vì nó trưởng thành và ổn định hoặc nó bị phồng lên và ghép nối.

Tài liệu người dùng

  • Trong khi chờ tài liệu kém, tôi có thể xem và xem {zero, giá trị âm, tập rỗng, v.v.} có được chấp nhận không và giá trị trả về dự kiến ​​là bao nhiêu.
  • Nó cũng đưa ra một ví dụ tốt về cách tôi nên sử dụng đối tượng / hàm

1
điều này dường như không cung cấp bất cứ điều gì đáng kể qua các điểm được thực hiện và giải thích trong các câu trả lời trước. Ngay cả "tóm tắt tốt đẹp" đã được đăng lên (theo ý tôi, nó không hay lắm nhưng ồ)
gnat
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.