Có đủ để sử dụng các bài kiểm tra chấp nhận và tích hợp thay vì kiểm tra đơn vị không?


62

Giới thiệu ngắn về câu hỏi này. Tôi đã sử dụng TDD và gần đây là BDD trong hơn một năm nay. Tôi sử dụng các kỹ thuật như chế giễu để làm cho bài kiểm tra của mình hiệu quả hơn. Gần đây tôi đã bắt đầu một dự án cá nhân để viết một chương trình quản lý tiền nhỏ cho mình. Vì tôi không có mã kế thừa nên đây là dự án hoàn hảo để bắt đầu với TDD. Thật không may, tôi đã không trải nghiệm niềm vui của TDD rất nhiều. Nó thậm chí còn làm hỏng niềm vui của tôi đến nỗi tôi đã từ bỏ dự án.

Có vấn đề gì thế? Vâng, tôi đã sử dụng phương pháp như TDD để cho phép các bài kiểm tra / yêu cầu phát triển thiết kế chương trình. Vấn đề là hơn một nửa thời gian phát triển như đối với các bài kiểm tra viết / tái cấu trúc. Vì vậy, cuối cùng tôi không muốn thực hiện thêm bất kỳ tính năng nào vì tôi sẽ cần phải cấu trúc lại và viết cho nhiều bài kiểm tra.

Trong công việc tôi có rất nhiều mã di sản. Ở đây tôi viết ngày càng nhiều bài kiểm tra tích hợp và chấp nhận và bài kiểm tra đơn vị ít hơn. Đây dường như không phải là một cách tiếp cận tồi vì các lỗi chủ yếu được phát hiện bởi các bài kiểm tra chấp nhận và tích hợp.

Ý tưởng của tôi là, cuối cùng tôi có thể viết nhiều bài kiểm tra tích hợp và chấp nhận hơn bài kiểm tra đơn vị. Giống như tôi đã nói để phát hiện lỗi, các bài kiểm tra đơn vị không tốt hơn các bài kiểm tra tích hợp / chấp nhận. Kiểm tra đơn vị cũng tốt cho thiết kế. Vì tôi thường viết rất nhiều trong số chúng, các lớp của tôi luôn được thiết kế để có thể kiểm tra tốt. Ngoài ra, cách tiếp cận để cho các thử nghiệm / yêu cầu hướng dẫn thiết kế dẫn trong hầu hết các trường hợp để thiết kế tốt hơn. Ưu điểm cuối cùng của bài kiểm tra đơn vị là chúng nhanh hơn. Tôi đã viết đủ các bài kiểm tra tích hợp để biết, rằng chúng có thể nhanh gần như các bài kiểm tra đơn vị.

Sau khi tôi xem qua web tôi phát hiện ra rằng có những ý tưởng rất giống với tôi được đề cập ở đâyở đó . Bạn nghĩ gì về ý tưởng này?

Biên tập

Trả lời các câu hỏi một ví dụ về thiết kế tốt, nhưng tôi cần một cấu trúc lại rất lớn cho yêu cầu tiếp theo:

Lúc đầu, có một số yêu cầu để thực hiện các lệnh nhất định. Tôi đã viết một trình phân tích cú pháp lệnh có thể mở rộng - trong đó phân tích cú pháp các lệnh từ một số loại dấu nhắc lệnh và gọi đúng lệnh trên mô hình. Kết quả được biểu diễn trong lớp mô hình khung nhìn: Thiết kế đầu tiên

Không có gì sai ở đây. Tất cả các lớp là độc lập với nhau và tôi có thể dễ dàng thêm các lệnh mới, hiển thị dữ liệu mới.

Yêu cầu tiếp theo là, mỗi lệnh nên có biểu diễn khung nhìn riêng - một số loại xem trước kết quả của lệnh. Tôi đã thiết kế lại chương trình để đạt được một thiết kế tốt hơn cho yêu cầu mới: Thiết kế thứ hai

Điều này cũng tốt vì bây giờ mỗi lệnh có mô hình khung nhìn riêng và do đó xem trước riêng.

Vấn đề là, trình phân tích cú pháp lệnh đã được thay đổi để sử dụng phân tích cú pháp dựa trên mã thông báo của các lệnh và bị tước khỏi khả năng thực thi các lệnh của nó. Mỗi lệnh có mô hình khung nhìn riêng và mô hình khung nhìn dữ liệu chỉ biết mô hình khung nhìn lệnh hiện tại, hơn là biết dữ liệu phải được hiển thị.

Tất cả những gì tôi muốn biết vào thời điểm này là, nếu thiết kế mới không phá vỡ bất kỳ yêu cầu hiện có nào. Tôi không phải thay đổi BẤT K of bài kiểm tra chấp nhận nào của mình. Tôi đã phải cấu trúc lại hoặc xóa gần MỌI bài kiểm tra đơn vị, đó là một đống công việc khổng lồ.

Những gì tôi muốn thể hiện ở đây là một tình huống phổ biến thường xảy ra trong quá trình phát triển. Không có vấn đề gì với các thiết kế cũ hay mới, chúng chỉ thay đổi tự nhiên với các yêu cầu - tôi hiểu nó như thế nào, đây là một lợi thế của TDD, rằng thiết kế phát triển.

Phần kết luận

Cảm ơn tất cả các câu trả lời và thảo luận. Tóm lại cuộc thảo luận này tôi đã nghĩ đến một cách tiếp cận mà tôi sẽ thử nghiệm với dự án tiếp theo của mình.

  • Trước hết tôi viết tất cả các bài kiểm tra trước khi thực hiện bất cứ điều gì như tôi luôn làm.
  • Đối với các yêu cầu đầu tiên tôi viết một số bài kiểm tra chấp nhận kiểm tra toàn bộ chương trình. Sau đó, tôi viết một số thử nghiệm tích hợp cho các thành phần mà tôi cần thực hiện yêu cầu. Nếu có một thành phần phối hợp chặt chẽ với một thành phần khác để thực hiện yêu cầu này, tôi cũng sẽ viết một số thử nghiệm tích hợp trong đó cả hai thành phần được thử nghiệm cùng nhau. Cuối cùng nhưng không kém phần quan trọng nếu tôi phải viết một thuật toán hoặc bất kỳ lớp nào khác có độ hoán vị cao - ví dụ: trình tuần tự hóa - tôi sẽ viết các bài kiểm tra đơn vị cho các lớp cụ thể này. Tất cả các lớp khác không được kiểm tra nhưng bất kỳ bài kiểm tra đơn vị.
  • Đối với lỗi quá trình có thể được đơn giản hóa. Thông thường một lỗi được gây ra bởi một hoặc hai thành phần. Trong trường hợp này tôi sẽ viết một bài kiểm tra tích hợp cho các thành phần kiểm tra lỗi. Nếu nó liên quan đến một thuật toán, tôi sẽ chỉ viết một bài kiểm tra đơn vị. Nếu không dễ dàng phát hiện thành phần xảy ra lỗi, tôi sẽ viết một bài kiểm tra chấp nhận để xác định vị trí lỗi - đây phải là một ngoại lệ.


Những câu hỏi này dường như giải quyết nhiều hơn vấn đề tại sao viết bài kiểm tra cả. Tôi muốn thảo luận nếu viết bài kiểm tra chức năng thay vì bài kiểm tra đơn vị có thể là một cách tiếp cận tốt hơn.
Yggdrasil

theo cách đọc của tôi, câu trả lời trong câu hỏi trùng lặp chủ yếu là về thời điểm các bài kiểm tra không đơn giản có ý nghĩa hơn
gnat

Liên kết đầu tiên đó là một bản sao. Hãy nghĩ rằng bạn có nghĩa là: lập trình
Robbie Dee

Các câu trả lời từ liên kết từ Robbie Dee thậm chí còn nhiều hơn về lý do để kiểm tra tất cả.
Yggdrasil

Câu trả lời:


37

Đó là so sánh cam và táo.

Kiểm tra tích hợp, kiểm tra chấp nhận, kiểm tra đơn vị, kiểm tra hành vi - tất cả chúng đều là kiểm tra và tất cả chúng sẽ giúp bạn cải thiện mã của mình nhưng chúng cũng khá khác nhau.

Theo quan điểm của tôi, tôi sẽ xem xét từng thử nghiệm khác nhau và hy vọng giải thích lý do tại sao bạn cần một sự pha trộn của tất cả chúng:

Kiểm tra tích hợp:

Đơn giản, hãy kiểm tra xem các phần thành phần khác nhau trong hệ thống của bạn có tích hợp chính xác không - ví dụ - có thể bạn mô phỏng yêu cầu dịch vụ web và kiểm tra xem kết quả có quay lại không. Tôi thường sẽ sử dụng dữ liệu tĩnh thực (ish) và các phụ thuộc bị chế giễu để đảm bảo rằng nó có thể được xác minh một cách nhất quán.

Các bài kiểm tra chấp nhận:

Một thử nghiệm chấp nhận nên tương quan trực tiếp đến một trường hợp sử dụng kinh doanh. Nó có thể rất lớn ("giao dịch được gửi chính xác") hoặc nhỏ ("bộ lọc thành công lọc danh sách") - không thành vấn đề; Vấn đề là nó phải được liên kết rõ ràng với một yêu cầu người dùng cụ thể. Tôi thích tập trung vào những thứ này để phát triển dựa trên thử nghiệm bởi vì điều đó có nghĩa là chúng tôi có một hướng dẫn tham khảo tốt về các thử nghiệm cho các câu chuyện của người dùng cho dev và qa để xác minh.

Bài kiểm tra đơn vị:

Đối với các đơn vị chức năng riêng biệt nhỏ có thể tạo ra hoặc không tạo nên một câu chuyện người dùng riêng lẻ - ví dụ: câu chuyện người dùng nói rằng chúng tôi truy xuất tất cả khách hàng khi chúng tôi truy cập một trang web cụ thể có thể là một thử nghiệm chấp nhận (mô phỏng đánh vào web trang và kiểm tra phản hồi) nhưng cũng có thể chứa một số kiểm tra đơn vị (xác minh rằng các quyền bảo mật đã được kiểm tra, xác minh rằng các truy vấn kết nối cơ sở dữ liệu chính xác, xác minh rằng bất kỳ mã nào giới hạn số lượng kết quả được thực thi chính xác) - đây đều là "kiểm tra đơn vị" đó không phải là một bài kiểm tra chấp nhận hoàn chỉnh.

Kiểm tra hành vi:

Xác định luồng nào sẽ là một ứng dụng trong trường hợp đầu vào cụ thể. Ví dụ: "khi kết nối không thể được thiết lập, hãy xác minh rằng hệ thống thử lại kết nối." Một lần nữa, đây không chắc là một thử nghiệm chấp nhận hoàn toàn nhưng nó vẫn cho phép bạn xác minh một cái gì đó hữu ích.

Đây là tất cả theo ý kiến ​​của tôi thông qua nhiều kinh nghiệm viết bài kiểm tra; Tôi không muốn tập trung vào các cách tiếp cận sách giáo khoa - thay vào đó, tập trung vào những gì mang lại giá trị bài kiểm tra của bạn.


Theo định nghĩa của bạn, tôi cho rằng điều tôi muốn nói là viết nhiều bài kiểm tra hành vi (?) Hơn bài kiểm tra đơn vị. Bài kiểm tra đơn vị đối với tôi là bài kiểm tra kiểm tra một lớp duy nhất với tất cả các phụ thuộc bị chế giễu. Có những trường hợp kiểm tra đơn vị là hữu ích nhất. Đó là ví dụ khi tôi viết một thuật toán phức tạp. Sau đó, tôi có nhiều ví dụ với đầu ra dự kiến ​​của thuật toán. Tôi muốn kiểm tra điều này ở cấp độ đơn vị vì nó thực sự nhanh hơn thử nghiệm hành vi. Tôi không thấy giá trị của kiểm tra một lớp ở cấp độ đơn vị chỉ có một bàn tay đầy đủ các đường dẫn qua lớp có thể dễ dàng được kiểm tra bằng kiểm tra hành vi.
Yggdrasil

14
Cá nhân tôi nghĩ rằng các bài kiểm tra chấp nhận là quan trọng nhất, kiểm tra hành vi rất quan trọng khi kiểm tra những thứ như giao tiếp, độ tin cậy và các trường hợp lỗi và kiểm tra đơn vị rất quan trọng khi kiểm tra các tính năng phức tạp nhỏ (thuật toán sẽ là một ví dụ tốt về điều này)
Michael

Tôi không quá vững với thuật ngữ của bạn. Chúng tôi lập trình một bộ lập trình. Trong đó tôi chịu trách nhiệm cho trình soạn thảo đồ họa. Các thử nghiệm của tôi kiểm tra trình soạn thảo với các dịch vụ bị chế giễu từ phần còn lại của bộ phần mềm và với giao diện người dùng bị chế giễu. Đó là loại thử nghiệm nào?
Yggdrasil

1
Phụ thuộc vào những gì bạn đang thử nghiệm - bạn có đang thử nghiệm các tính năng kinh doanh (thử nghiệm chấp nhận) không? Bạn đang thử nghiệm tích hợp (kiểm tra tích hợp)? Bạn đang kiểm tra những gì xảy ra khi bạn nhấp vào một nút (kiểm tra hành vi)? Bạn đang kiểm tra thuật toán (bài kiểm tra đơn vị)?
Michael

4
"Tôi không thích tập trung vào các cách tiếp cận sách giáo khoa - thay vào đó, tập trung vào những gì mang lại giá trị cho bài kiểm tra của bạn" Ồ, rất đúng! Câu hỏi đầu tiên luôn được đặt ra là "tôi giải quyết vấn đề gì bằng cách làm điều này?". Và dự án khác nhau có thể có vấn đề khác nhau để giải quyết!
Laurent Bourgault-Roy

40

TL; DR: Miễn là nó đáp ứng nhu cầu của bạn, vâng.

Tôi đã thực hiện phát triển Chấp nhận thử nghiệm (ATDD) trong nhiều năm nay. Nó có thể rất thành công. Có một vài điều cần chú ý.

  • Các bài kiểm tra đơn vị thực sự giúp thực thi IOC. Nếu không có kiểm tra đơn vị, trách nhiệm thuộc về các nhà phát triển để đảm bảo rằng họ đáp ứng các yêu cầu của mã được viết tốt (trong chừng mực các thử nghiệm đơn vị điều khiển mã được viết tốt)
  • Chúng có thể chậm hơn và có lỗi sai nếu bạn thực sự sử dụng các tài nguyên thường bị chế giễu.
  • Bài kiểm tra không xác định chính xác vấn đề cụ thể như bài kiểm tra đơn vị sẽ làm. Bạn cần phải điều tra thêm để sửa lỗi thất bại.

Bây giờ là lợi ích

  • Bảo hiểm thử nghiệm tốt hơn nhiều, bao gồm các điểm tích hợp.
  • Đảm bảo toàn bộ hệ thống đáp ứng các tiêu chí chấp nhận, đó là toàn bộ quan điểm phát triển phần mềm.
  • Làm cho các nhà tái cấu trúc lớn dễ dàng hơn nhiều, nhanh hơn và rẻ hơn.

Như mọi khi, bạn phải phân tích và tìm hiểu xem cách thực hành này có phù hợp với tình huống của bạn không. Không giống như nhiều người, tôi không nghĩ rằng có một câu trả lời đúng lý tưởng hóa. Nó sẽ phụ thuộc vào nhu cầu và yêu cầu của bạn.


8
Điểm tuyệt vời. Thật quá dễ dàng để trở thành một người không gian nhỏ bé trong việc thử nghiệm và viết hàng trăm trường hợp để có được một ánh sáng ấm áp của sự hài lòng khi nó "vượt qua" với màu sắc bay. Nói một cách đơn giản: nếu phần mềm của bạn không làm những gì nó cần làm theo quan điểm của NGƯỜI DÙNG, bạn đã thất bại trong bài kiểm tra đầu tiên và quan trọng nhất.
Robbie Dee

Điểm tốt để xác định chính xác vấn đề cụ thể. Nếu tôi có một yêu cầu rất lớn, tôi viết các bài kiểm tra chấp nhận để kiểm tra toàn bộ hệ thống và hơn là viết các bài kiểm tra kiểm tra các nhiệm vụ phụ của các thành phần nhất định của hệ thống để đạt được yêu cầu. Với điều này, tôi có thể xác định chính xác trong hầu hết các trường hợp thành phần có khiếm khuyết.
Yggdrasil

2
"Các bài kiểm tra đơn vị giúp thực thi IOC"?!? Tôi chắc chắn rằng bạn có nghĩa là DI ở đó thay vì IoC, nhưng dù sao, tại sao ai đó muốn thực thi việc sử dụng DI? Cá nhân, tôi thấy rằng trong thực tế DI dẫn đến phi đối tượng (lập trình theo kiểu thủ tục).
Rogério

Bạn có thể cung cấp đầu vào của bạn trên tùy chọn (tốt nhất IMO) để thực hiện tích hợp BÓNG và kiểm tra đơn vị so với đối số chỉ thực hiện kiểm tra tích hợp không? Câu trả lời của bạn ở đây là tốt, nhưng dường như đóng khung những thứ này là loại trừ lẫn nhau, điều mà tôi không tin là chúng có.
starmandeluxe

@starmandeluxe Họ thực sự không loại trừ lẫn nhau. Thay vào đó là một câu hỏi về giá trị bạn muốn nhận được từ thử nghiệm. Tôi sẽ kiểm tra đơn vị bất cứ nơi nào có giá trị vượt quá chi phí phát triển / hỗ trợ để viết bài kiểm tra đơn vị. Ví dụ. Tôi chắc chắn sẽ kiểm tra đơn vị hàm lãi kép trong một ứng dụng tài chính.
dietbuddha

18

Vâng, tôi đã sử dụng phương pháp như TDD để cho phép các bài kiểm tra / yêu cầu phát triển thiết kế chương trình. Vấn đề là hơn một nửa thời gian phát triển đối với các bài kiểm tra viết / tái cấu trúc

Kiểm tra đơn vị hoạt động tốt nhất khi giao diện chung của các thành phần mà chúng được sử dụng không thay đổi quá thường xuyên. Điều này có nghĩa là, khi các thành phần đã được thiết kế tốt (ví dụ, tuân theo các nguyên tắc RẮN).

Vì vậy, tin rằng một thiết kế tốt chỉ "tiến hóa" từ "ném" rất nhiều bài kiểm tra đơn vị vào một thành phần là sai lầm. TDD không phải là "giáo viên" cho thiết kế tốt, nó chỉ có thể giúp một chút để xác minh rằng các khía cạnh nhất định của thiết kế là tốt (đặc biệt là khả năng kiểm tra).

Khi yêu cầu của bạn thay đổi và bạn phải thay đổi phần bên trong của một thành phần và điều này sẽ phá vỡ 90% bài kiểm tra đơn vị của bạn, vì vậy bạn phải cấu trúc lại chúng rất thường xuyên, khi đó thiết kế có lẽ không tốt lắm.

Vì vậy, lời khuyên của tôi là: suy nghĩ về thiết kế của các thành phần bạn đã tạo và cách bạn có thể làm cho chúng nhiều hơn theo nguyên tắc mở / đóng. Ý tưởng của cái sau là đảm bảo chức năng của các thành phần của bạn có thể được mở rộng sau mà không thay đổi chúng (và do đó không phá vỡ API của thành phần được sử dụng trong các thử nghiệm đơn vị của bạn). Các thành phần như vậy có thể (và nên được) bao phủ bởi các bài kiểm tra đơn vị, và trải nghiệm không nên đau đớn như bạn đã mô tả.

Khi bạn không thể đưa ra một thiết kế như vậy ngay lập tức, các bài kiểm tra chấp nhận và tích hợp có thể thực sự là một khởi đầu tốt hơn.

EDIT: Đôi khi thiết kế của các thành phần của bạn có thể tốt, nhưng thiết kế của các bài kiểm tra đơn vị của bạn có thể gây ra vấn đề . Ví dụ đơn giản: Bạn muốn kiểm tra phương thức "MyMethod" của lớp X và viết

    var x= new X();
    Assert.AreEqual("expected value 1" x.MyMethod("value 1"));
    Assert.AreEqual("expected value 2" x.MyMethod("value 2"));
    // ...
    Assert.AreEqual("expected value 500" x.MyMethod("value 500"));

(giả sử các giá trị có một số loại ý nghĩa).

Giả sử thêm, trong mã sản xuất chỉ có một cuộc gọi đến X.MyMethod. Bây giờ, đối với một yêu cầu mới, phương thức "MyMethod" cần một tham số bổ sung (ví dụ, một cái gì đó giống như context), không thể bỏ qua. Nếu không có kiểm tra đơn vị, người ta sẽ phải cấu trúc lại mã cuộc gọi chỉ ở một nơi. Với các bài kiểm tra đơn vị, người ta phải cấu trúc lại 500 địa điểm.

Nhưng nguyên nhân ở đây không phải là đơn vị tự kiểm tra, đó chỉ là thực tế rằng cùng một lệnh gọi "X.MyMethod" được lặp đi lặp lại nhiều lần, không tuân thủ nghiêm ngặt nguyên tắc "Đừng lặp lại chính mình (DRY). ở đây là đưa dữ liệu thử nghiệm và các giá trị dự kiến ​​có liên quan vào danh sách và chạy các cuộc gọi đến "MyMethod" trong một vòng lặp (hoặc, nếu công cụ kiểm tra hỗ trợ cái gọi là "kiểm tra ổ dữ liệu", để sử dụng tính năng đó). số lượng vị trí cần thay đổi trong đơn vị kiểm tra khi chữ ký phương thức thay đổi thành 1 (trái ngược với 500).

Trong trường hợp thực tế của bạn, tình huống có thể phức tạp hơn, nhưng tôi hy vọng bạn hiểu ý - khi kiểm tra đơn vị của bạn sử dụng API thành phần mà bạn không biết liệu nó có thể thay đổi hay không, hãy đảm bảo bạn giảm số lượng các cuộc gọi đến API đó đến mức tối thiểu.


"Điều này có nghĩa là, khi các thành phần đã được thiết kế tốt.": Tôi đồng ý với bạn, nhưng làm thế nào các thành phần có thể được thiết kế nếu bạn viết các bài kiểm tra trước khi viết mã và mã thiết kế? Ít nhất đây là cách tôi đã hiểu TDD.
Giorgio

2
@Giorgio: thực ra, nó không thực sự quan trọng nếu bạn viết bài kiểm tra trước hay sau. Thiết kế có nghĩa là đưa ra quyết định về trách nhiệm của một thành phần, về giao diện công cộng, về sự phụ thuộc (trực tiếp hoặc được tiêm), về thời gian chạy hoặc hành vi thời gian biên dịch, về khả năng biến đổi, về tên, về luồng dữ liệu, luồng điều khiển, lớp, v.v. thiết kế cũng có nghĩa là trì hoãn một số quyết định đến thời điểm mới nhất có thể. Kiểm tra đơn vị có thể cho bạn thấy một cách gián tiếp nếu thiết kế của bạn ổn: nếu bạn muốn cấu trúc lại rất nhiều trong số chúng sau đó khi yêu cầu thay đổi, thì có lẽ là không.
Doc Brown

@Giorgio: một ví dụ có thể làm rõ: giả sử bạn có thành phần X với phương thức "MyMethod" và 2 tham số. Sử dụng TDD, bạn viết X x= new X(); AssertTrue(x.MyMethod(12,"abc"))trước khi thực sự thực hiện phương pháp. Sử dụng thiết kế trả trước, bạn có thể viết class X{ public bool MyMethod(int p, string q){/*...*/}}trước và viết các bài kiểm tra sau. Trong cả hai trường hợp, bạn đã đưa ra quyết định thiết kế giống nhau. Nếu quyết định là tốt hay xấu, TDD sẽ không cho bạn biết.
Doc Brown

1
Tôi đồng ý với bạn: Tôi hơi nghi ngờ khi thấy TDD áp dụng một cách mù quáng với giả định rằng nó sẽ tự động tạo ra thiết kế tốt. Hơn nữa, đôi khi TDD cản trở nếu thiết kế chưa rõ ràng: Tôi buộc phải kiểm tra các chi tiết trước khi tôi có cái nhìn tổng quan về những gì tôi đang làm. Vì vậy, nếu tôi hiểu chính xác, chúng tôi đồng ý. Tôi nghĩ rằng (1) thử nghiệm đơn vị giúp xác minh thiết kế nhưng thiết kế là một hoạt động riêng biệt và (2) TDD không phải lúc nào cũng là giải pháp tốt nhất vì bạn cần sắp xếp ý tưởng của mình trước khi bắt đầu viết thử nghiệm và TDD có thể làm bạn chậm lại điều này.
Giorgio

1
Một thời gian ngắn, các bài kiểm tra đơn vị có thể hiển thị các lỗ hổng trong thiết kế bên trong của một thành phần. Giao diện, điều kiện trước và sau phải được biết trước, nếu không bạn không thể tạo bài kiểm tra đơn vị. Vì vậy, thiết kế của thành phần những gì thành phần cần phải được thực hiện trước khi thử nghiệm đơn vị có thể được viết. Làm thế nào nó làm điều này - thiết kế cấp thấp hơn, thiết kế chi tiết hoặc thiết kế bên trong hoặc bất cứ điều gì bạn muốn gọi nó - có thể diễn ra sau khi bài kiểm tra đơn vị đã được viết.
Maarten Bodewes

9

Vâng, tất nhiên nó được.

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

  • một bài kiểm tra đơn vị là một phần nhỏ, mục tiêu của bài kiểm tra thực hiện một đoạn mã nhỏ. Bạn viết rất nhiều trong số chúng để đạt được phạm vi bảo hiểm mã tốt, để tất cả (hoặc phần lớn các bit vụng về) được kiểm tra.
  • một thử nghiệm tích hợp là một thử nghiệm lớn, rộng, thực hiện một bề mặt lớn của mã của bạn. Bạn viết một vài trong số chúng để đạt được phạm vi bảo hiểm mã tốt, để tất cả (hoặc phần lớn các bit vụng về) được kiểm tra.

Xem sự khác biệt tổng thể ....

Vấn đề là một trong phạm vi bảo hiểm mã, nếu bạn có thể đạt được một bài kiểm tra đầy đủ tất cả mã của mình bằng cách sử dụng thử nghiệm tích hợp / chấp nhận, thì không có vấn đề gì. Mã của bạn đã được kiểm tra. Đó là mục tiêu.

Tôi nghĩ rằng bạn có thể cần kết hợp chúng lại, vì mọi dự án dựa trên TDD sẽ yêu cầu một số thử nghiệm tích hợp chỉ để đảm bảo rằng tất cả các đơn vị thực sự hoạt động tốt với nhau (tôi biết từ kinh nghiệm rằng một cơ sở mã hóa được kiểm tra 100% không nhất thiết phải hoạt động khi bạn đặt tất cả chúng lại với nhau!)

Vấn đề thực sự đến từ việc dễ dàng kiểm tra, gỡ lỗi các lỗi và sửa chúng. Một số người thấy các bài kiểm tra đơn vị của họ rất tốt trong việc này, chúng nhỏ và đơn giản và dễ thất bại, nhưng nhược điểm là bạn phải sắp xếp lại mã của mình cho phù hợp với các công cụ kiểm tra đơn vị và viết rất nhiều trong số chúng. Một bài kiểm tra tích hợp khó viết hơn để bao gồm nhiều mã và bạn có thể sẽ phải sử dụng các kỹ thuật như ghi nhật ký để gỡ lỗi mọi lỗi (mặc dù, tôi muốn nói rằng dù sao bạn cũng phải làm điều này, bạn không thể kiểm tra lỗi đơn vị khi tại chỗ!).

Dù bằng cách nào, bạn vẫn nhận được mã thử nghiệm, bạn chỉ cần quyết định cơ chế nào phù hợp với bạn hơn. (Tôi sẽ kết hợp một chút, thử nghiệm các thuật toán phức tạp và kiểm tra tích hợp phần còn lại).


7
Không hoàn toàn đúng ... Với các thử nghiệm tích hợp, có thể có hai thành phần đều có lỗi, nhưng các lỗi của chúng đã bị loại bỏ trong thử nghiệm tích hợp. Nó không quan trọng lắm cho đến khi người dùng cuối sử dụng nó theo cách chỉ sử dụng một trong các thành phần này ...
Michael Shaw

1
Mã bảo hiểm! = Đã kiểm tra - ngoài các lỗi hủy bỏ lẫn nhau, còn các kịch bản bạn chưa từng nghĩ đến thì sao? Kiểm thử tích hợp là tốt để kiểm tra đường dẫn hạnh phúc nhưng tôi hiếm khi thấy kiểm thử tích hợp đầy đủ khi mọi thứ không ổn.
Michael

4
@Ptolemy Tôi nghĩ rằng sự hiếm có của 2 thành phần lỗi hủy lẫn nhau là rất xa, thấp hơn nhiều so với 2 thành phần làm việc can thiệp lẫn nhau.
gbjbaanb

2
@Michael sau đó bạn không đặt đủ nỗ lực vào thử nghiệm, tôi đã nói rằng việc kiểm tra tích hợp tốt sẽ khó khăn hơn vì các thử nghiệm phải chi tiết hơn nhiều. Bạn có thể cung cấp dữ liệu xấu trong kiểm tra tích hợp dễ dàng như trong thử nghiệm đơn vị. Kiểm thử tích hợp! = Con đường hạnh phúc. Đó là về việc thực hiện càng nhiều mã càng tốt, đó là lý do tại sao có các công cụ bảo hiểm mã cho bạn biết bao nhiêu mã của bạn đã được thực thi.
gbjbaanb

1
@Michael Khi tôi sử dụng các công cụ như Cucumber hoặc SpecFlow một cách chính xác, tôi có thể tạo các bài kiểm tra tích hợp cũng kiểm tra các trường hợp ngoại lệ và các tình huống cực kỳ nhanh như kiểm tra đơn vị. Nhưng tôi đồng ý nếu một lớp có nhiều hoán vị, tôi thích viết một bài kiểm tra đơn vị cho lớp này. Nhưng điều này sẽ ít xảy ra hơn so với việc có các lớp chỉ có một số ít đường dẫn.
Yggdrasil

2

Tôi nghĩ đó là một ý tưởng khủng khiếp.

Vì các thử nghiệm chấp nhận và thử nghiệm tích hợp chạm vào các phần rộng hơn của mã của bạn để kiểm tra một mục tiêu cụ thể, nên chúng sẽ cần tái cấu trúc nhiều hơn theo thời gian chứ không phải ít hơn. Tệ hơn nữa, vì chúng bao gồm các phần rộng của mã, chúng làm tăng thời gian bạn dành để theo dõi nguyên nhân gốc vì bạn có một khu vực rộng hơn để tìm kiếm.

Không, bạn thường nên viết thêm các bài kiểm tra đơn vị trừ khi bạn có một ứng dụng kỳ lạ có 90% UI hoặc một cái gì đó khác gây khó xử cho bài kiểm tra đơn vị. Nỗi đau mà bạn gặp phải không phải từ các bài kiểm tra đơn vị, mà là kiểm tra sự phát triển đầu tiên. Nói chung, bạn chỉ nên dành 1/3 thời gian của mình cho hầu hết các bài kiểm tra viết. Rốt cuộc, họ ở đó để phục vụ bạn chứ không phải ngược lại.


2
Thịt bò chính tôi nghe thấy chống lại TDD là nó phá vỡ dòng phát triển tự nhiên và thực thi chương trình phòng thủ ngay từ đầu. Nếu một lập trình viên đã chịu áp lực thời gian, họ có thể muốn cắt mã và đánh bóng nó sau. Tất nhiên, đáp ứng một thời hạn tùy ý với mã lỗi là nền kinh tế sai lầm.
Robbie Dee

2
Thật vậy, đặc biệt là "đánh bóng nó sau" dường như không bao giờ thực sự xảy ra - mọi đánh giá tôi làm khi nhà phát triển đẩy "nó cần ra ngoài, chúng tôi sẽ làm sau" khi tất cả chúng ta đều biết, điều đó sẽ không xảy ra - về mặt kỹ thuật nợ = nhà phát triển phá sản theo ý kiến ​​của tôi.
Michael

3
Câu trả lời có ý nghĩa với tôi, không biết tại sao nó lại có quá nhiều lỗi. Trích lời Mike Cohn: "Thử nghiệm đơn vị phải là nền tảng của chiến lược tự động hóa thử nghiệm vững chắc và như vậy đại diện cho phần lớn nhất của kim tự tháp. Các thử nghiệm đơn vị tự động rất tuyệt vời vì chúng cung cấp dữ liệu cụ thể cho một lập trình viên có lỗi và nó đã xảy ra dòng 47 " mountaingoatsoftware.com/blog/ từ
guillaume31

4
@ guillaume31 Chỉ vì một số người đã nói rằng họ tốt không có nghĩa là họ tốt. Theo kinh nghiệm của tôi, lỗi KHÔNG được phát hiện bởi các thử nghiệm đơn vị, bởi vì chúng đã được thay đổi thành yêu cầu mới lên phía trước. Ngoài ra hầu hết các lỗi là lỗi tích hợp. Do đó, tôi phát hiện hầu hết trong số họ với các bài kiểm tra tích hợp của tôi.
Yggdrasil

2
@Yggdrasil Tôi cũng có thể trích dẫn Martin Fowler: "Nếu bạn gặp lỗi trong bài kiểm tra cấp cao, không chỉ bạn có lỗi trong mã chức năng, bạn còn có bài kiểm tra đơn vị bị thiếu". martinfowler.com/bliki/TestPyramid.html Dù sao đi nữa, nếu kiểm tra tích hợp một mình làm việc cho bạn, thì tốt thôi. Kinh nghiệm của tôi là, trong khi cần thiết, chúng chậm hơn, cung cấp các thông báo lỗi ít chính xác hơn và ít cơ động hơn (kết hợp nhiều hơn) so với các bài kiểm tra đơn vị. Ngoài ra, tôi có xu hướng ít chứng minh tương lai hơn khi tôi viết các bài kiểm tra tích hợp - lý do về các kịch bản được hình thành trước (mis?) Thay vì tính chính xác của một đối tượng.
guillaume31

2

"Chiến thắng" với TDD, là một khi các bài kiểm tra đã được viết, chúng có thể được tự động hóa. Mặt trái của nó là nó có thể tiêu tốn một đoạn đáng kể của thời gian phát triển. Cho dù điều này thực sự làm chậm toàn bộ quá trình là moot. Đối số là thử nghiệm trả trước làm giảm số lượng lỗi được sửa ở cuối chu kỳ phát triển.

Đây là nơi mà BDD xuất hiện vì các hành vi có thể được bao gồm trong thử nghiệm đơn vị để quá trình này theo định nghĩa ít trừu tượng hơn và hữu hình hơn.

Rõ ràng, nếu có sẵn một lượng thời gian vô hạn, bạn sẽ thực hiện càng nhiều thử nghiệm các loại khác nhau càng tốt. Tuy nhiên, thời gian nói chung là hạn chế và thử nghiệm liên tục chỉ có hiệu quả chi phí đến một điểm.

Tất cả điều này dẫn đến kết luận rằng các thử nghiệm cung cấp giá trị cao nhất phải ở phía trước của quá trình. Bản thân điều này không tự động ủng hộ một loại thử nghiệm so với loại thử nghiệm khác - hơn nữa mỗi trường hợp phải được thực hiện dựa trên giá trị của nó.

Nếu bạn đang viết một tiện ích dòng lệnh để sử dụng cá nhân, bạn chủ yếu quan tâm đến các bài kiểm tra đơn vị. Trong khi một dịch vụ web cho biết, sẽ yêu cầu một lượng đáng kể thử nghiệm tích hợp / hành vi.

Trong khi hầu hết các loại thử nghiệm tập trung vào thứ có thể gọi là "đường đua", tức là thử nghiệm những gì được doanh nghiệp yêu cầu hiện nay, thử nghiệm đơn vị là tuyệt vời trong việc loại bỏ các lỗi tinh vi có thể xuất hiện trong các giai đoạn phát triển sau này. Vì đây là một lợi ích không thể đo lường được, nên nó thường bị bỏ qua.


1
Tôi viết các bài kiểm tra của mình trước và tôi viết đủ các bài kiểm tra để khắc phục hầu hết các lỗi. Đối với các lỗi mà bề mặt sau này. Điều này nghe có vẻ với tôi, rằng một yêu cầu đã thay đổi hoặc một yêu cầu mới xuất hiện. Hơn các bài kiểm tra tích hợp / hành vi cần phải được thay đổi, thêm vào. Nếu sau đó một lỗi được hiển thị trong một yêu cầu cũ, thử nghiệm của tôi cho điều này sẽ hiển thị nó. Đối với tự động hóa. tất cả các bài kiểm tra của tôi chạy tất cả các thời gian.
Yggdrasil

Ví dụ tôi đã nghĩ đến trong đoạn cuối là nơi nói rằng, một thư viện chỉ được sử dụng bởi một ứng dụng duy nhất nhưng sau đó có một yêu cầu kinh doanh để biến đây thành một thư viện có mục đích chung. Trong trường hợp này, nó có thể phục vụ bạn tốt hơn để có ít nhất một số thử nghiệm đơn vị thay vì viết các thử nghiệm tích hợp / hành vi mới cho mọi hệ thống bạn đính kèm vào thư viện.
Robbie Dee

2
Kiểm tra tự động và kiểm tra đơn vị là vấn đề hoàn toàn trực giao. Bất kỳ dự án tự tôn trọng sẽ có tích hợp tự động và thử nghiệm chức năng. Cấp, bạn không thường thấy các bài kiểm tra đơn vị thủ công, nhưng chúng có thể tồn tại (về cơ bản kiểm tra đơn vị thủ công là một tiện ích kiểm tra cho một số chức năng cụ thể).
Jan Hudec

Vâng thực sự. Đã có một thị trường hưng thịnh cho các công cụ của bên thứ 3 tự động tồn tại bên ngoài phạm vi phát triển trong một thời gian đáng kể.
Robbie Dee

1

Ưu điểm cuối cùng của bài kiểm tra đơn vị là chúng nhanh hơn. Tôi đã viết đủ các bài kiểm tra tích hợp để biết, rằng chúng có thể nhanh gần như các bài kiểm tra đơn vị.

Đây là điểm mấu chốt và không chỉ là "lợi thế cuối cùng". Khi dự án ngày càng lớn hơn, các bài kiểm tra chấp nhận tích hợp của bạn sẽ ngày càng chậm hơn. Và ở đây, ý tôi là chậm đến mức bạn sẽ ngừng thực thi chúng.

Tất nhiên, các bài kiểm tra đơn vị cũng trở nên chậm hơn, nhưng chúng vẫn nhanh hơn thứ tự cường độ nhanh hơn. Ví dụ, trong dự án trước đây của tôi (c ++, khoảng 600 kLOC, 4000 bài kiểm tra đơn vị và 200 bài kiểm tra tích hợp), mất khoảng một phút để thực hiện tất cả và sau đó 15 phút để thực hiện các bài kiểm tra tích hợp. Để xây dựng và thực hiện các bài kiểm tra đơn vị cho phần được thay đổi, trung bình sẽ mất ít hơn 30 giây. Khi bạn có thể làm điều đó quá nhanh, bạn sẽ muốn làm điều đó mọi lúc.

Chỉ cần làm rõ: Tôi không nói không thêm các bài kiểm tra tích hợp và chấp nhận, nhưng có vẻ như bạn đã làm TDD / BDD sai cách.

Kiểm tra đơn vị cũng tốt cho thiết kế.

Có, thiết kế với khả năng kiểm tra trong tâm trí sẽ làm cho thiết kế tốt hơn.

Vấn đề là hơn một nửa thời gian phát triển như đối với các bài kiểm tra viết / tái cấu trúc. Vì vậy, cuối cùng tôi không muốn thực hiện thêm bất kỳ tính năng nào vì tôi sẽ cần phải cấu trúc lại và viết cho nhiều bài kiểm tra.

Vâng, khi các yêu cầu thay đổi, bạn phải thay đổi mã. Tôi sẽ nói với bạn rằng bạn đã không hoàn thành công việc của mình nếu bạn không viết bài kiểm tra đơn vị. Nhưng điều này không có nghĩa là bạn nên có phạm vi bảo hiểm 100% với các bài kiểm tra đơn vị - đó không phải là mục tiêu. Một số thứ (như GUI hoặc truy cập tệp, ...) thậm chí không có nghĩa là đơn vị được kiểm tra.

Kết quả của điều này là chất lượng mã tốt hơn và một lớp thử nghiệm khác. Tôi sẽ nói rằng nó là giá trị nó.


Chúng tôi cũng đã có vài thử nghiệm chấp nhận 1000 năm và sẽ mất cả tuần để thực hiện tất cả.


1
Bạn đã xem ví dụ của tôi chưa? Điều này xảy ra tất cả các thời gian. Vấn đề là, khi tôi triển khai một tính năng mới, tôi thay đổi / thêm bài kiểm tra đơn vị để họ kiểm tra tính năng mới - do đó sẽ không có bài kiểm tra đơn vị nào bị phá vỡ. Trong hầu hết các trường hợp, tôi có tác dụng phụ của những thay đổi không được phát hiện bằng các thử nghiệm đơn vị - vì môi trường bị chế giễu. Theo kinh nghiệm của tôi vì điều này không có bài kiểm tra đơn vị nào từng nói với tôi rằng tôi đã phá vỡ một tính năng hiện có. Đó luôn là các bài kiểm tra tích hợp và chấp nhận cho tôi thấy những sai lầm của mình.
Yggdrasil

Đối với thời gian thực hiện. Với một ứng dụng ngày càng tăng, tôi chủ yếu có một số lượng lớn các thành phần bị cô lập. Nếu không tôi đã làm điều gì sai. Khi tôi thực hiện một tính năng mới, nó hầu như chỉ có trong một số thành phần hạn chế. Tôi viết một hoặc nhiều bài kiểm tra chấp nhận trong phạm vi của toàn bộ ứng dụng - có thể chậm. Ngoài ra, tôi viết các bài kiểm tra tương tự theo quan điểm thành phần - bài kiểm tra này nhanh, vì các thành phần thường nhanh. Tôi có thể thực hiện các bài kiểm tra thành phần mọi lúc, vì chúng đủ nhanh.
Yggdrasil

@Yggdrasil Như tôi đã nói, các bài kiểm tra đơn vị không phải là tất cả, nhưng chúng thường là lớp kiểm tra đầu tiên, vì chúng là bài kiểm tra nhanh nhất. Các xét nghiệm khác cũng hữu ích, và nên được kết hợp.
Bовић

1
Chỉ vì chúng nhanh hơn không có nghĩa, mà chúng nên được sử dụng chỉ vì điều này hoặc bởi vì nó là phổ biến để viết chúng. Giống như tôi đã nói các bài kiểm tra đơn vị của tôi không phá vỡ - vì vậy chúng không có giá trị nào đối với tôi.
Yggdrasil

1
Câu hỏi là, tôi có giá trị gì từ bài kiểm tra đơn vị, khi chúng không phá vỡ? Tại sao phải viết chúng, khi tôi luôn cần điều chỉnh chúng theo yêu cầu mới? Giá trị duy nhất từ ​​chúng tôi thấy là cho các thuật toán và các lớp khác có độ hoán vị cao. Nhưng đây là ít hơn các thử nghiệm thành phần và chấp nhận.
Yggdrasil
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.