Ý thức kiểm tra đơn vị mà không cần TDD


28

Chúng tôi có dự án mới (khá lớn) bắt đầu, mà chúng tôi dự định phát triển bằng TDD.

Ý tưởng về TDD đã thất bại (nhiều lý do kinh doanh và phi kinh doanh), nhưng ngay bây giờ chúng tôi có một cuộc trò chuyện - chúng tôi có nên viết bài kiểm tra đơn vị hay không. Bạn tôi nói rằng không có ý nghĩa (hoặc gần bằng không) khi viết bài kiểm tra đơn vị mà không có TDD, chúng ta chỉ nên tập trung vào các bài kiểm tra tích hợp. Tôi tin điều ngược lại, rằng vẫn còn một số ý nghĩa trong việc viết các bài kiểm tra đơn vị đơn giản, chỉ để làm cho mã tương lai nhiều hơn. Bạn nghĩ sao?

Đã thêm: Tôi nghĩ rằng đây không phải là bản sao của >> câu hỏi này << - Tôi hiểu sự khác biệt giữa UT và TDD. Câu hỏi của tôi không phảivề sự khác biệt , mà là về ý nghĩa của việc viết Bài kiểm tra đơn vị không có TDD.


22
Tôi tò mò không biết lý do gì mà bạn của bạn có lập trường ngớ ngẩn như vậy ...
Telastyn

11
Tôi muốn rằng phần lớn các dự án với một số bài kiểm tra đơn vị không sử dụng TDD.
Casey

2
Điều gì sẽ là cấp độ tích hợp của bạn? Đơn vị của bạn sẽ là gì? Tần suất bạn sẽ tái cấu trúc dưới mỗi cấp độ kiểm tra? Các bài kiểm tra tích hợp của bạn sẽ chạy nhanh như thế nào? Làm thế nào dễ dàng họ sẽ viết? Có bao nhiêu trường hợp tổ hợp làm các phần khác nhau trong mã của bạn tạo ra? vv ... Nếu bạn không biết câu trả lời cho những điều này, thì có lẽ còn quá sớm để đưa ra quyết định vững chắc. Đôi khi TDD là tuyệt vời. Đôi khi những lợi ích không rõ ràng. Đôi khi các bài kiểm tra đơn vị là rất cần thiết. Đôi khi một bộ kiểm tra tích hợp hợp lý mua cho bạn gần như nhiều, và linh hoạt hơn nhiều ... Giữ cho các tùy chọn của bạn mở.
topo Tái lập lại

2
Như một số lời khuyên thiết thực từ kinh nghiệm, đừng kiểm tra mọi thứ nếu bạn không làm TDD. Hãy xác định về những loại xét nghiệm có giá trị. Tôi đã thấy rằng các thử nghiệm đơn vị trên các phương thức đầu vào / đầu ra thuần túy có giá trị đặc biệt, trong khi các thử nghiệm tích hợp ở mức rất cao của ứng dụng (ví dụ, thực sự gửi yêu cầu web trên một ứng dụng web) cũng có giá trị đặc biệt. Xem ra cho các bài kiểm tra tích hợp giữa các lớp và bài kiểm tra đơn vị đòi hỏi nhiều thiết lập giả. Đồng thời xem video này: youtube.com/watch?v=R9FOchgTtLM .
jpmc26

Cập nhật của bạn không có ý nghĩa liên quan đến câu hỏi bạn đã hỏi. Nếu bạn hiểu sự khác biệt giữa TDD và Bài kiểm tra đơn vị, thì điều gì cản trở bạn viết bài kiểm tra đơn vị. Bỏ phiếu để đóng câu hỏi của bạn mặc dù tôi có thể thấy một đối số để đóng là "không rõ ràng về những gì bạn đang hỏi" thay vì trùng lặp.

Câu trả lời:


52

TDD được sử dụng chủ yếu (1) để đảm bảo phạm vi bảo hiểm, (2) và để lái thiết kế có thể bảo trì, dễ hiểu, có thể kiểm tra. Nếu bạn không sử dụng TDD, bạn sẽ không nhận được bảo hiểm mã. Nhưng điều đó không có nghĩa là bạn nên từ bỏ mục tiêu đó và hoàn toàn sống với mức bảo hiểm 0%.

Kiểm tra hồi quy đã được phát minh cho một lý do. Lý do là về lâu dài, chúng giúp bạn tiết kiệm nhiều thời gian hơn trong các lỗi được ngăn chặn hơn là chúng phải nỗ lực thêm để viết. Điều này đã được chứng minh nhiều lần. Vì vậy, trừ khi bạn đang thuyết phục nghiêm túc rằng tổ chức của bạn là nhiều, tốt hơn nhiều ở công nghệ phần mềm so với tất cả các bậc thầy người khuyên kiểm tra hồi quy (hoặc nếu bạn có kế hoạch đi xuống rất sớm để có không có chạy dài cho bạn), vâng, bạn hoàn toàn nên có các bài kiểm tra đơn vị, vì chính xác lý do áp dụng cho hầu hết mọi tổ chức khác trên thế giới: bởi vì họ bắt lỗi sớm hơn các bài kiểm tra tích hợp và điều đó sẽ giúp bạn tiết kiệm tiền. Không viết chúng giống như chuyển tiền miễn phí chỉ nằm quanh đường.


12
"Nếu bạn không sử dụng TDD, bạn sẽ không nhận được bảo hiểm mã được bảo đảm.": Tôi không nghĩ vậy. Bạn có thể phát triển trong hai ngày và trong hai ngày tiếp theo bạn viết bài kiểm tra. Điểm quan trọng là bạn không xem xét một tính năng đã hoàn thành cho đến khi bạn có phạm vi bảo hiểm mã mong muốn.
Giorgio

5
@DougM - Trong một thế giới lý tưởng có lẽ ...
Telastyn

7
Đáng buồn thay, TDD đi đôi với chế giễu và cho đến khi mọi người ngừng làm điều đó, điều đó chứng tỏ rằng bài kiểm tra của bạn chạy nhanh hơn . TDD đã chết. Thử nghiệm sống lâu.
MickyD

17
TDD không đảm bảo bảo hiểm mã. Đó là một giả định nguy hiểm. Bạn có thể mã chống lại các bài kiểm tra, vượt qua các bài kiểm tra đó, nhưng vẫn có trường hợp cạnh.
Robert Harvey

4
@MickyDuncan Tôi không chắc lắm Tôi hoàn toàn hiểu mối quan tâm của bạn. Mocking là một kỹ thuật hoàn toàn hợp lệ được sử dụng để cách ly một thành phần với các thành phần khác để các thử nghiệm về hành vi của thành phần đó có thể được thực hiện độc lập. Vâng, được đưa đến mức cực đoan, nó có thể dẫn đến phần mềm được thiết kế quá mức, nhưng vì vậy có thể có bất kỳ kỹ thuật phát triển nào nếu sử dụng không phù hợp. Bên cạnh đó, như DHH nêu trong bài viết mà bạn trích dẫn, ý tưởng chỉ sử dụng các bài kiểm tra toàn hệ thống cũng tệ như vậy, nếu không thực sự tồi tệ hơn. Điều quan trọng là sử dụng phán đoán để quyết định cách tốt nhất để kiểm tra bất kỳ tính năng cụ thể nào .
Jules

21

Tôi có một giai thoại liên quan từ một cái gì đó đang xảy ra ngay bây giờ cho tôi. Tôi đang tham gia một dự án không sử dụng TDD. Những người QA của chúng tôi đang đưa chúng tôi đi theo hướng đó, nhưng chúng tôi là một bộ trang phục nhỏ và đó là một quá trình dài, rút ​​ra.

Dù sao , gần đây tôi đã sử dụng thư viện của bên thứ ba để thực hiện một nhiệm vụ cụ thể. Có một vấn đề liên quan đến việc sử dụng thư viện đó, do đó, về cơ bản tôi đã tự mình viết một phiên bản của thư viện đó. Tổng cộng, nó đã trở thành khoảng 5.000 dòng mã thực thi và khoảng 2 tháng thời gian của tôi. Tôi biết các dòng mã là một số liệu kém, nhưng đối với câu trả lời này, tôi cảm thấy đó là một chỉ số tốt về độ lớn.

Có một cấu trúc dữ liệu cụ thể mà tôi cần, cho phép tôi theo dõi số lượng bit tùy ý. Vì dự án là ở Java, tôi đã chọn Java BitSetvà sửa đổi nó một chút (tôi cũng cần khả năng theo dõi các 0s hàng đầu , điều mà Bitset của Java không làm vì một số lý do .....). Sau khi đạt phạm vi bảo hiểm ~ 93%, tôi bắt đầu viết một số bài kiểm tra thực sự sẽ làm căng thẳng hệ thống mà tôi đã viết. Tôi cần phải đánh giá các khía cạnh nhất định của chức năng để đảm bảo chúng sẽ đủ nhanh cho các yêu cầu cuối cùng của tôi. Không có gì đáng ngạc nhiên, một trong những chức năng mà tôi đã ghi đè từ BitSetgiao diện bị chậm một cách vô lý khi xử lý các tập bit lớn (trong trường hợp này là hàng trăm triệu bit). Các chức năng ghi đè khác dựa vào chức năng này, vì vậy nó là một cổ chai lớn .

Cuối cùng, tôi đã đi đến bảng vẽ và tìm ra cách để điều khiển cấu trúc cơ bản của nó BitSet, đó là một long[]. Tôi đã thiết kế thuật toán, hỏi các đồng nghiệp về đầu vào của họ và sau đó tôi bắt đầu viết mã. Sau đó, tôi chạy thử nghiệm đơn vị. Một số trong số chúng đã bị hỏng, và những cái đã chỉ cho tôi chính xác nơi tôi cần tìm trong thuật toán của mình để sửa nó. Sau khi sửa tất cả các lỗi từ các bài kiểm tra đơn vị, tôi có thể nói rằng hàm này hoạt động như bình thường. Ít nhất, tôi có thể tự tin rằng thuật toán mới này hoạt động tốt như thuật toán trước đó.

Tất nhiên, đây không phải là bằng chứng đạn. Nếu có lỗi trong mã của tôi mà đơn vị kiểm tra không kiểm tra, thì tôi sẽ không biết. Nhưng tất nhiên, lỗi chính xác đó cũng có thể có trong thuật toán chậm hơn của tôi. Tuy nhiên , tôi có thể nói với một mức độ tin cậy cao rằng tôi không phải lo lắng về đầu ra sai từ chức năng cụ thể đó. Các thử nghiệm đơn vị có sẵn đã giúp tôi tiết kiệm hàng giờ, có lẽ là vài ngày, khi thử kiểm tra thuật toán mới để đảm bảo nó chính xác.

Đó là điểm có các bài kiểm tra đơn vị bất kể TDD - có nghĩa là, các bài kiểm tra đơn vị sẽ làm điều này cho bạn trong TDD và bên ngoài TDD đều giống nhau, khi bạn kết thúc việc tái cấu trúc / duy trì mã. Tất nhiên, điều này sẽ được kết hợp với kiểm tra thường xuyên hồi quy, kiểm tra khói, thử nghiệm mờ, vv, nhưng đơn vị thử nghiệm, như các tiểu bang tên, kiểm tra những thứ trên, mức độ nguyên tử nhỏ nhất có thể, mang đến cho bạn hướng vào nơi lỗi đã xuất hiện bất ngờ.

Trong trường hợp của tôi, nếu không có các bài kiểm tra đơn vị hiện có, bằng cách nào đó tôi sẽ phải đưa ra một phương pháp đảm bảo thuật toán hoạt động mọi lúc. Cuối cùng ... nghe có vẻ giống như thử nghiệm đơn vị , phải không?


7

Bạn có thể chia mã khoảng 4 loại:

  1. Đơn giản và hiếm khi thay đổi.
  2. Thay đổi đơn giản và thường xuyên.
  3. Phức tạp và hiếm khi thay đổi.
  4. Thay đổi phức tạp và thường xuyên.

Các bài kiểm tra đơn vị trở nên có giá trị hơn (có khả năng bắt được các lỗi quan trọng) càng đi sâu vào danh sách bạn đi. Trong các dự án cá nhân của tôi, tôi hầu như luôn làm TDD ở loại 4. Ở loại 3 tôi thường làm TDD trừ khi thử nghiệm thủ công đơn giản và nhanh hơn. Ví dụ, mã khử răng cưa sẽ phức tạp để viết, nhưng dễ xác minh trực quan hơn nhiều so với viết thử nghiệm đơn vị, vì vậy thử nghiệm đơn vị sẽ chỉ có giá trị với tôi nếu mã đó thay đổi thường xuyên. Phần còn lại của mã tôi chỉ đặt dưới kiểm tra đơn vị sau khi tôi tìm thấy một lỗi trong chức năng đó.

Đôi khi rất khó để biết trước loại nào mà một khối mã nhất định phù hợp. Giá trị của TDD là bạn không vô tình bỏ lỡ bất kỳ bài kiểm tra đơn vị phức tạp nào. Chi phí của TDD là tất cả thời gian bạn dành để viết các bài kiểm tra đơn vị đơn giản. Tuy nhiên, thông thường những người có kinh nghiệm với một dự án biết với mức độ chắc chắn hợp lý về loại phần khác nhau của mã phù hợp. Nếu bạn không làm TDD, ít nhất bạn nên cố gắng viết các bài kiểm tra có giá trị nhất.


1
Khi làm việc với mã như bạn đề xuất với ví dụ khử răng cưa của bạn, tôi thấy điều tốt nhất là phát triển mã bằng thực nghiệm, sau đó thêm một số thử nghiệm đặc tính để đảm bảo rằng tôi không vô tình phá vỡ thuật toán sau này. Các thử nghiệm đặc tính rất nhanh và dễ phát triển, vì vậy chi phí thực hiện việc này rất thấp.
Jules

1

Cho dù đó là bài kiểm tra đơn vị, thành phần, tích hợp hoặc chấp nhận, phần quan trọng là nó phải được tự động hóa. Không có kiểm tra tự động là một sai lầm nghiêm trọng đối với bất kỳ loại phần mềm nào, từ CRUD đơn giản đến các phép tính phức tạp nhất. Lý do là việc viết các bài kiểm tra tự động sẽ luôn có chi phí thấp hơn nhu cầu liên tục để chạy tất cả các bài kiểm tra theo cách thủ công khi bạn không thực hiện theo đơn đặt hàng lớn. Sau khi bạn viết chúng, bạn chỉ cần nhấn một nút để xem chúng có vượt qua hay thất bại. Các bài kiểm tra thủ công sẽ luôn mất nhiều thời gian để chạy và phụ thuộc vào con người (sinh vật sống chán, có thể thiếu chú ý và vân vân) để có thể kiểm tra xem các bài kiểm tra vượt qua hay thất bại. Tóm lại, luôn luôn viết bài kiểm tra tự động.

Bây giờ, về lý do tại sao đồng nghiệp của bạn có thể chống lại việc thực hiện bất kỳ loại thử nghiệm đơn vị nào mà không có TDD: Có lẽ vì khó tin tưởng các thử nghiệm được viết sau mã sản xuất. Và nếu bạn không thể tin tưởng vào các bài kiểm tra tự động của mình, chúng không có giá trị . Theo chu trình TDD, trước tiên bạn phải thực hiện một thử nghiệm thất bại (vì lý do đúng) để được phép viết mã sản xuất để vượt qua (và không còn nữa). Quá trình này về cơ bản là kiểm tra các bài kiểm tra của bạn, vì vậy bạn có thể tin tưởng chúng. Chưa kể đến việc viết các bài kiểm tra trước khi mã thực tế thúc đẩy bạn thiết kế các đơn vị và các thành phần của mình để dễ kiểm tra hơn (mức độ tách rời cao, áp dụng SRP, v.v ...). Mặc dù, tất nhiên, làm TDD có kỷ luật .

Thay vào đó, nếu bạn viết tất cả mã sản xuất trước, khi bạn viết các bài kiểm tra cho nó, bạn sẽ mong chúng vượt qua ở lần chạy đầu tiên. Điều này rất có vấn đề, bởi vì bạn có thể đã tạo một thử nghiệm bao gồm 100% mã sản xuất của bạn, mà không xác nhận hành vi chính xác (thậm chí có thể không thực hiện bất kỳ xác nhận nào! Tôi đã thấy điều này xảy ra ), vì bạn không thể thấy nó thất bại đầu tiên để kiểm tra nếu nó không đúng lý do. Vì vậy, bạn có thể có dương tính giả. Kết quả dương tính giả cuối cùng sẽ phá vỡ niềm tin vào bộ thử nghiệm của bạn, về cơ bản buộc mọi người phải dùng đến thử nghiệm thủ công một lần nữa, do đó bạn có chi phí cho cả hai quy trình (viết thử nghiệm + kiểm tra thủ công).

Điều này có nghĩa là bạn phải tìm một cách khác để kiểm tra các bài kiểm tra của mình , giống như TDD. Vì vậy, bạn dùng đến việc gỡ lỗi, bình luận các phần của mã sản xuất, v.v., để có thể tin tưởng vào các bài kiểm tra. Vấn đề là quá trình "kiểm tra bài kiểm tra của bạn" chậm hơn nhiều theo cách này. Thêm thời gian này vào thời gian bạn sẽ sử dụng để chạy thử nghiệm đặc biệt theo cách thủ công (vì bạn không có kiểm tra tự động trong khi bạn đang mã hóa mã sản xuất), theo kinh nghiệm của tôi, kết quả là một quá trình tổng thể chậm hơn nhiều so với thực hành TDD "theo cuốn sách" (Kent Beck - TDD bằng ví dụ). Ngoài ra, tôi sẵn sàng đặt cược ở đây và nói rằng thực sự "kiểm tra bài kiểm tra của bạn" sau khi chúng được viết cần nhiều kỷ luật hơn TDD.

Vì vậy, có thể nhóm của bạn có thể xem xét lại "lý do kinh doanh và phi kinh doanh" vì không làm TDD. Theo kinh nghiệm của tôi, mọi người có xu hướng nghĩ TDD chậm hơn so với việc chỉ viết các bài kiểm tra đơn vị sau khi mã được thực hiện. Giả định này là thiếu sót, như bạn đã đọc ở trên.


0

Thông thường chất lượng của các xét nghiệm phụ thuộc vào xuất xứ của họ. Tôi thường xuyên phạm tội vì không thực hiện TDD 'thực' - Tôi viết một số mã để chứng minh rằng chiến lược tôi muốn sử dụng thực sự có hiệu quả, sau đó đề cập đến từng trường hợp mã có nghĩa là hỗ trợ cho các thử nghiệm sau đó. Thông thường đơn vị mã là một lớp, để cung cấp cho bạn một ý tưởng chung về số lượng công việc tôi sẽ vui vẻ làm mà không có phạm vi kiểm tra - có nghĩa là, không phải là một số tiền lớn. Điều này có nghĩa là ý nghĩa ngữ nghĩa của các bài kiểm tra phù hợp độc đáo với hệ thống được kiểm tra ở trạng thái 'hoàn thành' - bởi vì tôi đã viết cho họ biết những trường hợp nào mà SUT đáp ứng và cách nó hoàn thành chúng.

Ngược lại, TDD với chính sách tái cấu trúc mạnh mẽ có xu hướng lỗi thời các bài kiểm tra ít nhất là nhanh như bạn có thể viết chúng dưới dạng giao diện chung của hệ thống khi thay đổi kiểm tra. Cá nhân tôi thấy khối lượng công việc tinh thần của cả việc thiết kế các đơn vị chức năng của ứng dụng giữ cho ngữ nghĩa của các bài kiểm tra bao gồm nó quá cao để duy trì sự tập trung của tôi và bảo trì kiểm tra thường xuyên bị trượt. Các cơ sở mã kết thúc với các thử nghiệm treo xung quanh mà không kiểm tra bất cứ thứ gì có giá trị hoặc hoàn toàn sai. Nếu bạn có kỷ luật và năng lực tinh thần để luôn cập nhật bộ kiểm tra, hãy luyện tập TDD một cách nghiêm ngặt như bạn muốn. Tôi không, vì vậy tôi thấy nó ít thành công hơn vì lý do đó.


0

Thật ra chú Bob đã đề cập đến một điểm rất thú vị trong một trong những video Clean Coders của mình. Ông nói rằng chu trình Red-Green-Refactor có thể được áp dụng theo 2 cách.

1 là cách TDD thông thường. Viết một bài kiểm tra thất bại sau đó thực hiện bài kiểm tra vượt qua và cuối cùng là cấu trúc lại.

Cách thứ 2 là viết một đoạn mã sản xuất rất nhỏ và ngay lập tức làm theo bằng cách kiểm tra đơn vị của nó sau đó tái cấu trúc.

Ý tưởng là đi trong các bước rất nhỏ . Tất nhiên bạn mất xác minh từ mã sản xuất rằng thử nghiệm của bạn chuyển từ màu đỏ sang màu xanh lá cây, nhưng trong một số trường hợp tôi làm việc chủ yếu với các nhà phát triển cơ sở, những người đã từ chối thậm chí cố gắng hiểu TDD, điều đó tỏ ra có hiệu quả.

Một lần nữa tôi nhắc lại (và điều này đã được chú Bob nhấn mạnh) ý tưởng là đi theo những bước rất nhỏ và ngay lập tức kiểm tra đoạn mã sản xuất vừa được thêm vào.


"... ý tưởng là thực hiện từng bước rất nhỏ và ngay lập tức kiểm tra đoạn mã sản xuất vừa được thêm vào.": Tôi không đồng ý. Những gì bạn mô tả nếu tốt khi bạn đã có một ý tưởng rõ ràng về những gì bạn muốn làm và bạn muốn làm việc trên các chi tiết, nhưng bạn cần phải có được bức tranh lớn trước. Nếu không, bằng cách thực hiện các bước rất nhỏ (kiểm tra, phát triển, kiểm tra, phát triển), bạn có thể bị lạc trong các chi tiết. "Nếu bạn không biết bạn đang đi đâu, bạn có thể không đến đó."
Giorgio
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.