Làm thế nào để làm thử nghiệm phát triển


15

Tôi chỉ có hơn 2 năm kinh nghiệm trong việc phát triển ứng dụng. Trong hai năm đó, cách tiếp cận phát triển của tôi như sau

  1. Phân tích yêu cầu
  2. Thành phần / Đối tượng nhận dạng, Các chức năng cần thiết, Hành vi, Quy trình và các ràng buộc của chúng
  3. Tạo các lớp, mối quan hệ giữa chúng, các ràng buộc về hành vi & trạng thái của đối tượng
  4. Tạo chức năng, xử lý với các ràng buộc hành vi theo yêu cầu
  5. Ứng dụng kiểm tra thủ công
  6. Nếu thay đổi yêu cầu sửa đổi thành phần / chức năng, sau đó kiểm tra ứng dụng theo cách thủ công

Gần đây tôi đã được giới thiệu về TDD và cảm thấy rằng đây là cách rất tốt để phát triển vì mã được phát triển có lý do mạnh mẽ để tồn tại và rất nhiều vấn đề triển khai bài được giảm nhẹ.

Nhưng vấn đề của tôi là tôi không thể tạo thử nghiệm trước, thay vào đó tôi đang xác định các thành phần và chỉ viết thử nghiệm cho chúng trước khi tôi thực sự viết các thành phần. câu hỏi của tôi là

  1. Tôi đang làm nó là đúng? Nếu không chính xác những gì tôi phải thay đổi
  2. Có cách nào bạn có thể xác định xem bài kiểm tra bạn đã viết có đủ không?
  3. Có phải là một thực hành tốt để viết bài kiểm tra cho chức năng rất đơn giản có thể tương đương với 1 + 1 = 2 hoặc nó chỉ là một trò chơi quá sức?
  4. Có tốt để thay đổi chức năng và kiểm tra phù hợp nếu yêu cầu thay đổi?

2
"Tôi đang xác định các thành phần và chỉ viết thử nghiệm cho chúng trước khi tôi thực sự viết các thành phần.": Tôi thấy điều này đúng: trước tiên bạn xác định kiến ​​trúc thô của hệ thống của bạn và sau đó bắt đầu mã hóa. Trong quá trình mã hóa (TDD), bạn tìm ra các chi tiết của các thành phần riêng lẻ và có thể phát hiện ra các vấn đề với kiến ​​trúc của bạn mà bạn có thể khắc phục trên đường đi. Nhưng tôi thấy ổn khi bạn không bắt đầu viết mã mà không có bất kỳ phân tích nào trước đó.
Giorgio

Bạn cũng có thể xem xét thực hiện kiểm tra đơn vị / tích hợp tự động mà không cần thực hiện TDD. Hai người thường bị nhầm lẫn, nhưng họ không giống nhau.
Andres F.

Câu trả lời:


19

Tôi đang làm nó là đúng? Nếu không chính xác những gì tôi phải thay đổi

Thật khó để nói chỉ từ mô tả ngắn đó, nhưng tôi nghi ngờ rằng, không, bạn không làm đúng. Lưu ý: Tôi không nói rằng những gì bạn đang làm không hoạt động hoặc theo một cách nào đó là xấu, nhưng bạn không làm TDD. Chữ "D" ở giữa có nghĩa là "Driven", các bài kiểm tra thúc đẩy mọi thứ, quá trình phát triển, mã, thiết kế, kiến ​​trúc, mọi thứ .

Các bài kiểm tra cho bạn biết nên viết gì, khi nào nên viết nó, viết gì tiếp theo, khi nào nên dừng viết. Họ cho bạn biết thiết kế và kiến ​​trúc. (Thiết kế và kiến ​​trúc xuất hiện từ mã thông qua tái cấu trúc.) TDD không phải là về thử nghiệm. Nó thậm chí không phải là về việc viết bài kiểm tra trước: TDD là về việc để các bài kiểm tra thúc đẩy bạn, viết chúng trước tiên chỉ là điều kiện tiên quyết cần thiết cho việc đó.

Không quan trọng bạn thực sự viết mã xuống hay viết mã đầy đủ: bạn đang viết mã (bộ xương) trong đầu, sau đó viết bài kiểm tra cho mã đó. Đó không phải là TDD.

Buông bỏ thói quen đó thật khó . Thực sự, thực sự khó khăn. Nó dường như là đặc biệt khó khăn cho các lập trình viên có kinh nghiệm.

Keith Braithwaite đã tạo ra một bài tập mà anh gọi là TDD As If You Mete It . Nó bao gồm một bộ quy tắc (dựa trên Ba quy tắc TDD của chú Bob Martin , nhưng chặt chẽ hơn nhiều) mà bạn phải tuân thủ nghiêm ngặt và được thiết kế để hướng bạn áp dụng TDD chặt chẽ hơn. Nó hoạt động tốt nhất với lập trình cặp (để cặp của bạn có thể đảm bảo bạn không vi phạm các quy tắc) và một người hướng dẫn.

Các quy tắc là:

  1. Viết chính xác một bài kiểm tra mới, bài kiểm tra nhỏ nhất mà bạn có thể chỉ ra theo hướng của một giải pháp
  2. Thấy nó thất bại; thất bại biên dịch được tính là thất bại
  3. Làm cho bài kiểm tra từ (1) vượt qua bằng cách viết mã thực hiện ít nhất bạn có thể trong phương thức kiểm tra .
  4. Tái cấu trúc để loại bỏ trùng lặp, và nếu không theo yêu cầu để cải thiện thiết kế. Hãy nghiêm ngặt về việc sử dụng các động thái này:
    1. bạn muốn có một phương thức mới, hãy đợi cho đến khi tái cấu trúc thời gian, sau đó, bạn tạo ra các phương thức mới (không thử nghiệm) bằng cách thực hiện một trong những phương thức này và không có cách nào khác:
      • ưa thích: thực hiện Phương thức trích xuất trên mã thực hiện được tạo theo (3) để tạo một phương thức mới trong lớp thử nghiệm, hoặc
      • nếu bạn phải: di chuyển mã triển khai theo (3) sang một phương thức triển khai hiện có
    2. bạn muốn có một lớp mới chờ đợi cho đến khi tái cấu trúc thời gian, sau đó, bạn tạo các lớp không thử nghiệm để cung cấp đích cho Phương thức di chuyển và không vì lý do nào khác
    3. Tạo các lớp triển khai với các phương thức bằng cách thực hiện Phương thức di chuyển và không có cách nào khác

Thông thường, điều này sẽ dẫn đến các thiết kế rất khác so với "phương pháp giả TDD" đã thực hành trong đầu của bạn về thiết kế nên là gì, sau đó viết các bài kiểm tra để buộc thiết kế đó, thực hiện thiết kế mà bạn đã hình dung trước khi viết kiểm tra ".

Khi một nhóm người thực hiện một cái gì đó giống như trò chơi tic tac toe bằng cách sử dụng giả TDD, họ thường kết thúc với các thiết kế rất giống nhau liên quan đến một loại Boardlớp nào đó với mảng 3 × 3 Integers. Và ít nhất một phần các lập trình viên sẽ thực sự viết lớp này mà không cần kiểm tra vì họ "biết rằng họ sẽ cần nó" hoặc "cần một cái gì đó để viết bài kiểm tra của họ". Tuy nhiên, khi bạn buộc cùng nhóm đó áp dụng TDD As If You Mete It, họ sẽ thường kết thúc với sự đa dạng của các thiết kế rất khác nhau, thường không sử dụng bất cứ thứ gì thậm chí từ xa tương tự như a Board.

Có cách nào bạn có thể xác định xem bài kiểm tra bạn đã viết có đủ không?

Khi họ bao gồm tất cả các yêu cầu kinh doanh. Các thử nghiệm là một mã hóa của các yêu cầu hệ thống.

Có phải là một thực hành tốt để viết bài kiểm tra cho chức năng rất đơn giản có thể tương đương với 1 + 1 = 2 hoặc nó chỉ là một trò chơi quá sức?

Một lần nữa, bạn có nó ngược: bạn không viết bài kiểm tra cho chức năng. Bạn viết chức năng cho các bài kiểm tra. Nếu chức năng để vượt qua bài kiểm tra hóa ra là tầm thường, thì thật tuyệt! Bạn vừa hoàn thành một yêu cầu hệ thống và thậm chí không phải làm việc chăm chỉ cho nó!

Có tốt để thay đổi chức năng và kiểm tra phù hợp nếu yêu cầu thay đổi?

Không. Cách khác vòng. Nếu một yêu cầu thay đổi, bạn thay đổi thử nghiệm tương ứng với yêu cầu đó, xem nó thất bại, sau đó thay đổi mã để thực hiện. Các bài kiểm tra luôn luôn đến đầu tiên.

Thật khó để làm điều này. Bạn cần hàng chục, có thể hàng trăm giờ luyện tập có chủ ý để xây dựng một loại "bộ nhớ cơ" nào đó để đi đến điểm, khi thời hạn xuất hiện và bạn phải chịu áp lực, bạn thậm chí không phải nghĩ về nó và làm điều này trở thành cách nhanh nhất và tự nhiên nhất để làm việc.


1
Một câu trả lời rất rõ ràng thực sự! Từ quan điểm thực tế, một khung kiểm tra linh hoạt và mạnh mẽ rất thú vị khi thực hành TDD. Mặc dù độc lập với TDD, khả năng tự động chạy thử nghiệm là vô giá để gỡ lỗi một ứng dụng. Để bắt đầu với TDD, các chương trình không xen kẽ (kiểu UNIX) có lẽ là dễ nhất, vì trường hợp sử dụng có thể được kiểm tra bằng cách so sánh trạng thái thoát và đầu ra của chương trình với những gì được mong đợi. Một ví dụ cụ thể về phương pháp này có thể được tìm thấy trong thư viện Xăng của tôi cho OCaml.
Michael Le Barbier Grünewald

4
Bạn nói "khi bạn buộc cùng nhóm đó áp dụng TDD Như thể bạn tham gia, họ sẽ thường kết thúc với sự đa dạng của các thiết kế rất khác nhau, thường không sử dụng bất cứ thứ gì thậm chí từ xa tương tự như một Hội đồng" như thể đó là một điều tốt . Tôi không rõ ràng rằng đó là một điều tốt, và thậm chí có thể xấu từ quan điểm bảo trì vì có vẻ như việc triển khai sẽ rất phản cảm với người mới. Bạn có thể giải thích tại sao sự đa dạng thực hiện này là một điều tốt, hoặc ít nhất là không xấu?
Jim Clay

3
+1 Câu trả lời rất hay ở chỗ nó mô tả chính xác TDD. Tuy nhiên, nó cũng cho thấy tại sao TDD là một phương pháp thiếu sót: cần suy nghĩ cẩn thận và thiết kế rõ ràng, đặc biệt là khi phải đối mặt với các vấn đề thuật toán. Làm TDD "trong mù" (như TDD quy định) bằng cách giả vờ không có bất kỳ kiến ​​thức tên miền nào dẫn đến khó khăn và bế tắc không cần thiết. Xem sự thất bại của người giải Sudoku khét tiếng (phiên bản ngắn: TDD không thể đánh bại kiến ​​thức tên miền).
Andres F.

1
@AndresF .: Trên thực tế, các bài viết trên blog bạn liên quan đến dường như vang những kinh nghiệm Keith thực hiện khi làm TDD Như Nếu bạn có nghĩa là nó: khi làm "pseudo-TDD" cho Tic-Tac-Toe, họ bắt đầu bằng cách tạo ra một Boardlớp học với một Mảng 3x3 của ints (hoặc đại loại như thế). Trong khi đó, nếu bạn buộc họ làm TDDAIYMI, họ thường sẽ tạo ra một DSL nhỏ để nắm bắt kiến ​​thức miền. Tất nhiên đó chỉ là giai thoại. Một nghiên cứu hợp lý và khoa học sẽ tốt, nhưng như thường thấy trong các nghiên cứu như thế này, chúng quá nhỏ hoặc quá đắt.
Jörg W Mittag

@ JörgWMittag Sửa lỗi cho tôi nếu tôi hiểu lầm bạn, nhưng bạn có nói rằng Ron Jeffries đang làm "giả-TDD" không? Đó không phải là một dạng ngụy biện "không có người Scotland thực sự" sao? (Tôi đồng ý với bạn về sự cần thiết của các nghiên cứu khoa học hơn; blog tôi liên kết chỉ là một giai thoại đầy màu sắc về sự thất bại ngoạn mục của một trường hợp sử dụng TDD cụ thể. trong số chúng tôi để có một phân tích thực sự về metholody này và lợi ích bị cáo buộc của nó).
Andres F.

5

Bạn mô tả phương pháp phát triển của mình là một quá trình "chỉ từ trên xuống" - bạn bắt đầu từ mức độ trừu tượng cao hơn và ngày càng đi sâu vào chi tiết. TDD, ít nhất là ở dạng phổ biến, là một kỹ thuật "từ dưới lên". Và đối với một người làm việc chủ yếu là "từ trên xuống" thì thực sự rất bất thường khi làm việc "từ dưới lên".

Vậy, làm thế nào bạn có thể mang thêm "TDD" vào quá trình phát triển của mình? Đầu tiên, tôi cho rằng quá trình phát triển thực tế của bạn không phải lúc nào cũng "từ trên xuống" như bạn đã mô tả ở trên. Sau bước 2, có lẽ bạn sẽ xác định được một số thành phần độc lập với các thành phần khác. Đôi khi bạn quyết định thực hiện những thành phần đó đầu tiên. Các chi tiết về API công khai của các thành phần đó có thể không tuân theo các yêu cầu của bạn, các chi tiết cũng tuân theo các quyết định thiết kế của bạn. Đây là điểm mà bạn có thể bắt đầu với TDD: hãy tưởng tượng cách bạn sẽ sử dụng thành phần này và cách bạn thực sự sẽ sử dụng API. Và khi bạn bắt đầu mã hóa việc sử dụng API như vậy dưới dạng thử nghiệm, bạn mới bắt đầu với TDD.

Thứ hai, bạn có thể thực hiện TDD ngay cả khi bạn sẽ mã hóa "từ trên xuống" nhiều hơn, bắt đầu với các thành phần phụ thuộc vào các thành phần khác, không tồn tại trước tiên. Điều bạn phải học là làm thế nào để "chế nhạo" những phụ thuộc khác này trước. Điều đó sẽ cho phép bạn tạo và kiểm tra các thành phần cấp cao trước khi chuyển đến các thành phần cấp thấp hơn. Một ví dụ rất chi tiết về việc thực hiện TDD theo cách từ trên xuống có thể được tìm thấy trong bài đăng trên blog này của Ralf Hampal .


3

Tôi đang làm nó là đúng? Nếu không chính xác những gì tôi phải thay đổi

Bạn đang làm tốt

Có cách nào bạn có thể xác định xem bài kiểm tra bạn đã viết có đủ không?

Có, sử dụng một công cụ kiểm tra / mã bảo hiểm . Martin Fowler cung cấp một số lời khuyên tốt về bảo hiểm thử nghiệm.

Có phải là một thực hành tốt để viết bài kiểm tra cho chức năng rất đơn giản có thể tương đương với 1 + 1 = 2 hoặc nó chỉ là một trò chơi quá sức?

Nói chung, bất kỳ chức năng, phương pháp, thành phần, vv mà bạn mong đợi mang lại một số kết quả cho một số đầu vào là một ứng cử viên tốt cho một bài kiểm tra đơn vị. Tuy nhiên, như với hầu hết mọi thứ trong cuộc sống (kỹ thuật), bạn cần xem xét sự đánh đổi của mình: Liệu nỗ lực có được bù đắp bằng cách viết bài kiểm tra đơn vị dẫn đến cơ sở mã ổn định hơn trong dài hạn không? Nói chung, trước tiên hãy chọn viết mã kiểm tra cho chức năng quan trọng / quan trọng. Sau này nếu bạn thấy có lỗi liên quan đến một số phần chưa được kiểm tra của mã, hãy thêm các bài kiểm tra.

Có tốt để thay đổi chức năng và kiểm tra phù hợp nếu yêu cầu thay đổi?

Điều tốt khi có các bài kiểm tra tự động là bạn sẽ thấy ngay nếu một thay đổi phá vỡ các xác nhận trước đó. Nếu bạn mong đợi điều này vì yêu cầu thay đổi, có thể thay đổi mã kiểm tra (thực tế, trong TDD thuần túy, bạn sẽ thay đổi các thử nghiệm trước theo yêu cầu, sau đó chấp nhận mã cho đến khi đáp ứng yêu cầu mới).


Mã bảo hiểm có thể không phải là biện pháp rất đáng tin cậy. Việc thực thi% bảo hiểm thường dẫn đến rất nhiều thử nghiệm không cần thiết (như thử nghiệm cho tất cả các tham số null, v.v. - đó là các thử nghiệm vì lợi ích của các thử nghiệm gần như không có giá trị) và lãng phí thời gian phát triển, trong khi khó kiểm tra mã đường dẫn có thể không được kiểm tra ở tất cả.
Paul

3

Viết bài kiểm tra đầu tiên là một cách tiếp cận hoàn toàn khác nhau để viết phần mềm. Các thử nghiệm không chỉ là một công cụ xác minh chức năng mã phù hợp (tất cả đều vượt qua) mà là lực lượng xác định thiết kế. Mặc dù phạm vi kiểm tra có thể là một số liệu hữu ích, nhưng bản thân nó không phải là mục tiêu - mục tiêu của TDD không phải là đạt được% bảo hiểm mã tốt, mà là suy nghĩ về khả năng kiểm tra mã của bạn trước khi viết mã.

Nếu bạn gặp rắc rối với bài kiểm tra viết trước tiên, tôi khuyên bạn nên thực hiện một phiên lập trình cặp với người có kinh nghiệm về TDD, để bạn có được trải nghiệm về "cách suy nghĩ" về toàn bộ cách tiếp cận.

Một điều tốt để làm là xem video trực tuyến nơi phần mềm đang được phát triển bằng TDD từ dòng đầu tiên của nó. Một điều hay mà tôi từng giới thiệu về TDD là Hãy chơi TDD của James Shore. Hãy xem, nó sẽ minh họa cách thiết kế nổi dần hoạt động, những câu hỏi nào bạn nên tự hỏi mình trong khi viết bài kiểm tra và cách các lớp và phương thức mới được tạo, tái cấu trúc và lặp lại.

Có cách nào bạn có thể xác định xem bài kiểm tra bạn đã viết có đủ không?

Tôi tin rằng đây là câu hỏi sai. Khi bạn làm TDD, bạn đã chọn làm TDD và thiết kế nổi dần như là cách để viết phần mềm. Nếu bất kỳ chức năng mới nào bạn cần thêm luôn bắt đầu bằng một bài kiểm tra, nó sẽ luôn ở đó.

Có phải là một thực hành tốt để viết bài kiểm tra cho chức năng rất đơn giản có thể tương đương với 1 + 1 = 2 hoặc nó chỉ là một trò chơi quá sức?

Rõ ràng nó phụ thuộc, sử dụng phán đoán của bạn. Tôi không muốn viết kiểm tra các tham số null, nếu phương thức không phải là một phần của API công khai, nhưng nếu không, tại sao bạn không xác nhận rằng phương thức Add (a, b) trả về a + b thực sự?

Có tốt để thay đổi chức năng và kiểm tra phù hợp nếu yêu cầu thay đổi?

Một lần nữa, khi bạn thay đổi hoặc thêm chức năng mới vào mã của mình, bạn bắt đầu bằng một thử nghiệm, cho dù đó là thêm thử nghiệm mới hoặc thay đổi thử nghiệm hiện có khi yêu cầu thay đổi.

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.