it-swarm-vi.com

Làm thế nào để viết bài kiểm tra đơn vị "tốt"?

Bị kích hoạt bởi chủ đề này , tôi (một lần nữa) đang suy nghĩ về việc cuối cùng sử dụng các bài kiểm tra đơn vị trong các dự án của mình. Một vài áp phích ở đó có nội dung như "Các bài kiểm tra rất tuyệt, nếu chúng là các bài kiểm tra tốt". Câu hỏi của tôi bây giờ: các bài kiểm tra "tốt" là gì?

Trong các ứng dụng của tôi, phần chính thường là một số loại phân tích số, tùy thuộc vào lượng lớn dữ liệu được quan sát và dẫn đến một hàm phù hợp có thể được sử dụng để mô hình hóa dữ liệu này. Tôi thấy rất khó để xây dựng các thử nghiệm cho các phương thức này, vì số lượng đầu vào và kết quả có thể quá lớn để chỉ kiểm tra mọi trường hợp và bản thân các phương thức này thường khá dài và không thể dễ dàng được cấu trúc lại mà không làm giảm hiệu suất. Tôi đặc biệt quan tâm đến các bài kiểm tra "tốt" cho loại phương pháp này.

63
Jens

Nghệ thuật kiểm tra đơn vị có những điều sau đây để nói về kiểm tra đơn vị:

Một bài kiểm tra đơn vị nên có các thuộc tính sau:

  • Nó nên được tự động và lặp lại.
  • Nó phải dễ thực hiện.
  • Một khi nó viết bằng văn bản, nó sẽ vẫn được sử dụng trong tương lai.
  • Bất cứ ai cũng có thể chạy nó.
  • Nó sẽ chạy ở nút ấn.
  • Nó sẽ chạy nhanh.

và sau đó thêm nó nên hoàn toàn tự động, đáng tin cậy, dễ đọc và có thể bảo trì.

Tôi thực sự khuyên bạn nên đọc cuốn sách này nếu bạn chưa có.

Theo tôi, tất cả những thứ này đều rất quan trọng, nhưng ba đặc điểm cuối cùng (đáng tin cậy, dễ đọc và có thể duy trì) đặc biệt, như thể các bài kiểm tra của bạn có ba thuộc tính này thì mã của bạn cũng thường có chúng.

52
Andy Lowry

Một bài kiểm tra đơn vị tốt không phản ánh chức năng mà nó đang kiểm tra.

Như một ví dụ rất đơn giản, hãy xem xét bạn có một hàm trả về trung bình hai int. Kiểm tra toàn diện nhất sẽ gọi hàm và kiểm tra xem kết quả thực tế có phải là trung bình không. Điều này hoàn toàn không có ý nghĩa gì: bạn đang phản chiếu (sao chép) chức năng bạn đang kiểm tra. Nếu bạn mắc lỗi trong hàm chính, bạn sẽ mắc lỗi tương tự trong bài kiểm tra.

Nói cách khác, nếu bạn thấy mình sao chép chức năng chính trong bài kiểm tra đơn vị, đó có thể là một dấu hiệu cho thấy bạn đang lãng phí thời gian.

43
mojuba

Các bài kiểm tra đơn vị tốt về cơ bản là đặc điểm kỹ thuật ở dạng runnable:

  1. mô tả hành vi của mã tương ứng với các trường hợp sử dụng
  2. bao gồm các trường hợp góc kỹ thuật (điều gì xảy ra nếu null được thông qua) - nếu không có kiểm tra cho trường hợp góc, hành vi không được xác định.
  3. phá vỡ nếu mã được kiểm tra thay đổi từ đặc điểm kỹ thuật

Tôi đã thấy Test-Driven-Development rất phù hợp với thói quen của thư viện vì về cơ bản bạn viết API trước và THÌ việc triển khai thực tế.

10
user1249

đối với TDD, các tính năng kiểm tra "tốt" mà khách hàng muốn ; các tính năng không nhất thiết phải tương ứng với các chức năng và các kịch bản thử nghiệm không được nhà phát triển tạo ra trong chân không

trong trường hợp của bạn - tôi đoán - 'tính năng' là chức năng phù hợp mô hình hóa dữ liệu đầu vào trong một khả năng chịu lỗi nhất định. Vì tôi không biết bạn đang làm gì, tôi đang làm gì đó; hy vọng nó là analgous.

Ví dụ câu chuyện:

Là một [Phi công cánh X] tôi muốn [không quá 0,0001% lỗi phù hợp] để [máy tính nhắm mục tiêu có thể chạm vào cổng xả của Death Star khi di chuyển hết tốc độ qua hẻm núi hộp]

Vì vậy, bạn đi nói chuyện với các phi công (và với máy tính nhắm mục tiêu, nếu có tình cảm). Đầu tiên bạn nói về những gì là 'bình thường', sau đó nói về những điều bất thường. Bạn tìm ra những gì thực sự quan trọng trong kịch bản này, những gì là phổ biến, những gì không thể và những gì chỉ có thể.

Giả sử thông thường bạn sẽ có một cửa sổ nửa giây trên bảy kênh dữ liệu đo từ xa: tốc độ, cao độ, cuộn, ngáp, vectơ đích, kích thước mục tiêu và vận tốc mục tiêu và các giá trị này sẽ không đổi hoặc thay đổi tuyến tính. Bất thường, bạn có thể có ít kênh hơn và/hoặc các giá trị có thể thay đổi nhanh chóng. Vì vậy cùng nha bạn đưa ra một số thử nghiệm như:

//Scenario 1 - can you hit the side of a barn?
Given:
    all 7 channels with no dropouts for the full half-second window,
When:
    speed is zero
    and target velocity is zero
    and all other values are constant,
Then:
    the error coefficient must be zero

//Scenario 2 - can you hit a turtle?
Given:
    all 7 channels with no dropouts for the full half-second window,
When:
    speed is zero
    and target velocity is less than c
    and all other values are constant,
Then:
    the error coefficient must be less than 0.0000000001/ns

...

//Scenario 42 - death blossom
Given:
    all 7 channels with 30% dropout and a 0.05 second sampling window
When:
    speed is zero
    and position is within enemy cluster
    and all targets are stationary
Then:
    the error coefficient must be less than 0.000001/ns for each target

Bây giờ, bạn có thể nhận thấy rằng không có kịch bản nào cho tình huống cụ thể được mô tả trong câu chuyện. Hóa ra, sau khi nói chuyện với khách hàng và các bên liên quan khác, mục tiêu đó trong câu chuyện gốc chỉ là một ví dụ giả định. Các thử nghiệm thực sự ra khỏi các cuộc thảo luận tiếp theo. Điều này có thể xảy ra. Câu chuyện nên được viết lại, nhưng nó không phải là [vì câu chuyện chỉ là một phần giữ chỗ cho một cuộc trò chuyện với khách hàng].

7
Steven A. Lowe

Tạo các thử nghiệm cho các trường hợp góc, như một bộ thử nghiệm chỉ chứa số lượng đầu vào tối thiểu (có thể là 1 hoặc 0) và một vài trường hợp tiêu chuẩn. Những bài kiểm tra đơn vị này không phải là sự thay thế cho các bài kiểm tra chấp nhận kỹ lưỡng, cũng không nên như vậy.

5
user281377

Tôi đã thấy rất nhiều trường hợp mọi người đầu tư rất nhiều nỗ lực để viết các bài kiểm tra cho mã hiếm khi được nhập và không viết các bài kiểm tra cho mã được nhập thường xuyên.

Trước khi ngồi xuống để viết bất kỳ bài kiểm tra nào, bạn nên xem xét một số loại biểu đồ cuộc gọi, để đảm bảo bạn có kế hoạch bảo hiểm đầy đủ.

Ngoài ra, tôi không tin vào việc viết bài kiểm tra chỉ vì mục đích nói "Vâng, chúng tôi kiểm tra điều đó". Nếu tôi đang sử dụng một thư viện bị bỏ và sẽ không thay đổi, tôi sẽ không lãng phí một ngày để viết bài kiểm tra để đảm bảo các bộ phận của API sẽ không bao giờ thay đổi hoạt động như mong đợi, ngay cả khi một số phần nhất định của nó cao trên biểu đồ cuộc gọi. Các thử nghiệm mà tiêu thụ thư viện cho biết (mã của riêng tôi) chỉ ra điều này.

5
Tim Post

Không hoàn toàn như vậy TDD, nhưng sau khi bạn đã đi vào QA, bạn có thể cải thiện các bài kiểm tra của mình bằng cách thiết lập các trường hợp kiểm tra để tái tạo bất kỳ lỗi nào phát sinh trong quá trình QA. Điều này có thể đặc biệt có giá trị khi bạn tham gia hỗ trợ dài hạn và bạn bắt đầu đến một nơi mà bạn có nguy cơ vô tình giới thiệu lại các lỗi cũ. Có một bài kiểm tra tại chỗ để nắm bắt đó là đặc biệt có giá trị.

4
glenatron

Tôi cố gắng để có mọi bài kiểm tra chỉ kiểm tra một điều. Tôi cố gắng cung cấp cho mỗi bài kiểm tra một tên như ShouldDoSthing (). Tôi cố gắng kiểm tra hành vi, không thực hiện. Tôi chỉ thử nghiệm phương pháp công cộng.

Tôi thường có một hoặc một vài bài kiểm tra để thành công, và sau đó có thể là một bài kiểm tra thất bại, theo phương pháp công khai.

Tôi sử dụng mock-up rất nhiều. Một khung giả lập tốt có lẽ sẽ khá hữu ích, chẳng hạn như PowerMock. Mặc dù tôi chưa sử dụng.

Nếu lớp A sử dụng lớp B khác, tôi sẽ thêm giao diện X, để A không sử dụng B trực tiếp. Sau đó, tôi sẽ tạo XMockup giả và sử dụng nó thay vì B trong các thử nghiệm của mình. Nó thực sự giúp tăng tốc độ thực hiện kiểm tra, giảm độ phức tạp của thử nghiệm và cũng giảm số lượng thử nghiệm tôi viết cho A vì tôi không phải đối phó với các đặc thù của B. Tôi có thể ví dụ thử nghiệm mà A gọi là X.someMethod () thay vì tác dụng phụ của việc gọi B.someMethod ().

Giữ cho bạn kiểm tra mã sạch sẽ là tốt.

Khi sử dụng API, chẳng hạn như lớp cơ sở dữ liệu, tôi sẽ mô phỏng nó và cho phép giả lập để đưa ra một ngoại lệ ở mọi cơ hội có thể có trong lệnh. Sau đó, tôi chạy các bài kiểm tra một mà không cần ném, và trong một vòng lặp, mỗi lần ném một ngoại lệ vào cơ hội tiếp theo cho đến khi bài kiểm tra thành công trở lại. Một chút giống như các bài kiểm tra bộ nhớ có sẵn cho Symbian.

3
Roger C S Wernersson

Tôi thấy rằng Andry Lowry đã đăng các số liệu kiểm tra đơn vị của Roy Osherove; nhưng dường như không ai đưa ra bộ (miễn phí) mà chú Bob đưa ra Mã sạch (132-133). Anh ấy sử dụng từ viết tắt FIRST (ở đây với bản tóm tắt của tôi):

  • Nhanh (họ nên chạy nhanh, vì vậy mọi người sẽ không chạy chúng)
  • Độc lập (các bài kiểm tra không nên thực hiện thiết lập hoặc chia nhỏ cho nhau)
  • Lặp lại (nên chạy trên tất cả các môi trường/nền tảng)
  • Tự xác thực (hoàn toàn tự động; đầu ra phải là "vượt qua" hoặc "không thành công", không phải là tệp nhật ký)
  • Kịp thời (khi nào nên viết chúng trước khi viết mã sản xuất mà họ kiểm tra)
2
Kazark