Dữ liệu ngẫu nhiên trong bài kiểm tra đơn vị?


136

Tôi có một đồng nghiệp viết các bài kiểm tra đơn vị cho các đối tượng điền vào các trường của họ với dữ liệu ngẫu nhiên. Lý do của anh là nó cho phạm vi thử nghiệm rộng hơn, vì nó sẽ kiểm tra rất nhiều giá trị khác nhau, trong khi đó một thử nghiệm thông thường chỉ sử dụng một giá trị tĩnh duy nhất.

Tôi đã đưa cho anh ta một số lý do khác nhau để chống lại điều này, những lý do chính là:

  • giá trị ngẫu nhiên có nghĩa là thử nghiệm không thực sự lặp lại (điều đó cũng có nghĩa là nếu thử nghiệm có thể ngẫu nhiên thất bại, nó có thể làm như vậy trên máy chủ xây dựng và phá vỡ bản dựng)
  • nếu đó là một giá trị ngẫu nhiên và thử nghiệm thất bại, chúng ta cần phải a) sửa đối tượng và b) buộc bản thân phải kiểm tra giá trị đó mỗi lần, vì vậy chúng ta biết nó hoạt động, nhưng vì ngẫu nhiên chúng ta không biết giá trị đó là gì

Một đồng nghiệp khác đã thêm:

  • Nếu tôi đang kiểm tra một ngoại lệ, các giá trị ngẫu nhiên sẽ không đảm bảo rằng thử nghiệm kết thúc ở trạng thái mong đợi
  • dữ liệu ngẫu nhiên được sử dụng để tuôn ra một hệ thống và thử nghiệm tải, không phải cho các thử nghiệm đơn vị

Bất cứ ai khác có thể thêm lý do tôi có thể cho anh ta để anh ta ngừng làm điều này?

(Hoặc thay vào đó, đây có phải là một phương pháp viết bài kiểm tra đơn vị được chấp nhận và tôi và đồng nghiệp khác của tôi đã sai?)


32
"Giá trị ngẫu nhiên có nghĩa là thử nghiệm không thực sự lặp lại" không đúng, vì các giá trị sẽ sử dụng các số giả ngẫu nhiên. Cung cấp cùng một hạt giống ban đầu, có được cùng một chuỗi các thử nghiệm "ngẫu nhiên".
Raedwald

11
Giai thoại: Tôi đã từng viết một lớp xuất CSV và kiểm tra ngẫu nhiên cho thấy một lỗi khi các ký tự điều khiển được đặt ở cuối một ô. Nếu không có thử nghiệm ngẫu nhiên, tôi sẽ không bao giờ nghĩ rằng thêm nó như một trường hợp thử nghiệm. Có phải nó luôn thất bại? Không. Có phải là một bài kiểm tra hoàn hảo? Không. Nó có giúp tôi bắt và sửa lỗi không? Đúng.
Tyzoid

1
Các thử nghiệm cũng có thể đóng vai trò là tài liệu, để giải thích khi nào mã dự kiến ​​là đầu vào và những gì được mong đợi là đầu ra. Có một thử nghiệm với dữ liệu tùy ý rõ ràng có thể đơn giản và giải thích nhiều hơn mã tạo ra dữ liệu ngẫu nhiên.
thanh nẹp

Nếu thử nghiệm đơn vị của bạn không thành công do giá trị được tạo ngẫu nhiên và giá trị này không phải là một phần của khẳng định, chúc may mắn với việc gỡ lỗi thử nghiệm đơn vị của bạn.
eriksmith200

Câu trả lời:


72

Có một sự thỏa hiệp. Đồng nghiệp của bạn thực sự là một cái gì đó, nhưng tôi nghĩ rằng anh ta đang làm sai. Tôi không chắc chắn rằng thử nghiệm hoàn toàn ngẫu nhiên là rất hữu ích, nhưng chắc chắn nó không hợp lệ.

Một đặc tả chương trình (hoặc đơn vị) là một giả thuyết cho rằng có tồn tại một số chương trình đáp ứng nó. Chương trình sau đó là bằng chứng của giả thuyết đó. Những gì đơn vị thử nghiệm nên là một nỗ lực để cung cấp bằng chứng phản bác để bác bỏ rằng chương trình hoạt động theo thông số kỹ thuật.

Bây giờ, bạn có thể viết các bài kiểm tra đơn vị bằng tay, nhưng nó thực sự là một nhiệm vụ cơ học. Nó có thể được tự động. Tất cả bạn phải làm là viết thông số kỹ thuật và một máy có thể tạo ra rất nhiều bài kiểm tra đơn vị cố gắng phá mã của bạn.

Tôi không biết bạn đang sử dụng ngôn ngữ nào, nhưng xem tại đây:

Java http://feftaljava.org/

Scala (hoặc Java) http://github.com/rickynils/scalacheck

Haskell http://www.cs.chalmers.se/~rjmh/QuickCheck/

.NET: http://bloss.msdn.com/dsyme/archive/2008/08/09/fscheck-0-2.aspx

Các công cụ này sẽ lấy thông số kỹ thuật được định dạng tốt của bạn làm đầu vào và tự động tạo bao nhiêu bài kiểm tra đơn vị bạn muốn, với dữ liệu được tạo tự động. Họ sử dụng các chiến lược "thu hẹp" (mà bạn có thể điều chỉnh) để tìm trường hợp thử nghiệm đơn giản nhất có thể để phá mã của bạn và để đảm bảo rằng nó bao quát tốt các trường hợp cạnh.

Chúc bạn thử nghiệm vui vẻ!


1
+1 cho điều này. ScalaCheck thực hiện một công việc phi thường là tạo ra dữ liệu thử nghiệm ngẫu nhiên, tối thiểu hóa theo cách lặp lại.
Daniel Spiewak

17
Nó không phải là ngẫu nhiên. Đó là tùy ý. Sự khác biệt lớn :)
Apocalisp

reductiotest.org bây giờ dường như còn tồn tại và Google đã không chỉ cho tôi bất cứ nơi nào khác. Bất cứ ý tưởng bây giờ nó đang ở đâu?
Raedwald

Bây giờ nó là một phần của thư viện Java chức năng. Liên kết chỉnh sửa. Nhưng tôi sẽ chỉ sử dụng Scalacheck để kiểm tra mã Java.
Apocalisp

ScalaCheck đã chuyển đến GitHub. Liên kết cập nhật trong câu trả lời. Nó cũng hữu ích cho Java, không chỉ Scala. (Liên kết cũ là code.google.com/p/scalacheck )
RobertB

38

Loại thử nghiệm này được gọi là thử nghiệm Khỉ . Khi được thực hiện đúng, nó có thể hút hết bọ từ các góc thực sự tối.

Để giải quyết mối quan tâm của bạn về khả năng tái tạo: cách đúng để tiếp cận vấn đề này, là ghi lại các mục kiểm tra thất bại, tạo một bài kiểm tra đơn vị, thăm dò cho toàn bộ họ lỗi cụ thể; và bao gồm trong bài kiểm tra đơn vị một đầu vào cụ thể (từ dữ liệu ngẫu nhiên) gây ra lỗi ban đầu.


26

Có một ngôi nhà nửa đường ở đây có một số công dụng, đó là gieo mầm PRNG của bạn với một hằng số. Điều đó cho phép bạn tạo dữ liệu 'ngẫu nhiên' có thể lặp lại.

Cá nhân tôi nghĩ rằng có những nơi mà dữ liệu ngẫu nhiên (không đổi) hữu ích trong việc kiểm tra - sau khi bạn nghĩ rằng bạn đã thực hiện tất cả các góc được suy nghĩ cẩn thận của mình, sử dụng các kích thích từ PRNG đôi khi có thể tìm thấy những thứ khác.


4
Tôi đã thấy điều này hoạt động tốt trên một hệ thống có rất nhiều khóa và chủ đề. Hạt giống 'ngẫu nhiên' đã được ghi vào một tệp trong mỗi lần chạy, sau đó nếu một lần chạy thất bại, chúng ta có thể tìm ra đường dẫn mà mã đã thực hiện và viết một bài kiểm tra đơn vị viết tay cho trường hợp mà chúng ta đã bỏ lỡ.
Ian Ringrose

PRNG có nghĩa là gì?
systemovich

Trình tạo số ngẫu nhiên giả
Will Dean

16

Trong cuốn sách Beautiful Code , có một chương gọi là "Thử nghiệm đẹp", nơi anh ta trải qua một chiến lược thử nghiệm cho thuật toán Tìm kiếm nhị phân . Một đoạn được gọi là "Hành vi thử nghiệm ngẫu nhiên", trong đó anh ta tạo ra các mảng ngẫu nhiên để kiểm tra kỹ thuật toán. Bạn có thể đọc một số nội dung này trực tuyến tại Google Sách, trang 95 , nhưng đó là một cuốn sách tuyệt vời đáng để có.

Vì vậy, về cơ bản, điều này chỉ cho thấy rằng việc tạo dữ liệu ngẫu nhiên để thử nghiệm là một lựa chọn khả thi.


16

Tôi ủng hộ các bài kiểm tra ngẫu nhiên, và tôi viết chúng. Tuy nhiên, liệu chúng có phù hợp trong một môi trường xây dựng cụ thể không và chúng nên được đưa vào bộ thử nghiệm nào trong câu hỏi nhiều sắc thái hơn.

Chạy cục bộ (ví dụ, qua đêm trên hộp dev của bạn) các thử nghiệm ngẫu nhiên đã tìm thấy các lỗi cả rõ ràng và tối nghĩa. Những cái tối nghĩa là đủ phức tạp mà tôi nghĩ rằng thử nghiệm ngẫu nhiên thực sự là thử nghiệm thực tế duy nhất để loại bỏ chúng. Để thử nghiệm, tôi đã lấy một lỗi khó tìm thấy được phát hiện thông qua thử nghiệm ngẫu nhiên và có một nửa tá nhà phát triển crack xem xét chức năng (khoảng một chục dòng mã) nơi nó xảy ra. Không ai có thể phát hiện ra nó.

Nhiều đối số của bạn chống lại dữ liệu ngẫu nhiên là hương vị của "bài kiểm tra không thể lặp lại". Tuy nhiên, một thử nghiệm ngẫu nhiên được viết tốt sẽ nắm bắt hạt giống được sử dụng để bắt đầu hạt giống ngẫu nhiên và đưa ra thất bại. Ngoài việc cho phép bạn lặp lại thử nghiệm bằng tay, điều này cho phép bạn tạo ra thử nghiệm mới một cách tầm thường nhằm kiểm tra vấn đề cụ thể bằng cách mã hóa hạt giống cho thử nghiệm đó. Tất nhiên, có thể tốt hơn để mã hóa một bài kiểm tra rõ ràng bao gồm trường hợp đó, nhưng sự lười biếng có những ưu điểm của nó và điều này thậm chí cho phép bạn tự động tạo ra các trường hợp thử nghiệm mới từ một hạt giống thất bại.

Tuy nhiên, một điểm bạn đưa ra mà tôi không thể tranh luận là nó phá vỡ các hệ thống xây dựng. Hầu hết các bài kiểm tra tích hợp và liên tục đều mong muốn các bài kiểm tra sẽ làm điều tương tự, mọi lúc. Vì vậy, một bài kiểm tra ngẫu nhiên thất bại sẽ tạo ra sự hỗn loạn, thất bại ngẫu nhiên và chỉ tay vào những thay đổi vô hại.

Sau đó, một giải pháp là vẫn chạy các thử nghiệm ngẫu nhiên của bạn như là một phần của thử nghiệm xây dựng và CI, nhưng chạy nó với một hạt giống cố định, cho một số lần lặp cố định . Do đó, bài kiểm tra luôn làm điều tương tự, nhưng vẫn khám phá một loạt không gian đầu vào (nếu bạn chạy nó cho nhiều lần lặp).

Tại địa phương, ví dụ, khi thay đổi lớp liên quan, bạn có thể tự do chạy nó để lặp lại nhiều hơn hoặc với các hạt giống khác. Nếu thử nghiệm ngẫu nhiên trở nên phổ biến hơn, bạn thậm chí có thể tưởng tượng một bộ thử nghiệm cụ thể được biết là ngẫu nhiên, có thể được chạy với các hạt khác nhau (do đó tăng độ bao phủ theo thời gian) và trong đó thất bại không có nghĩa tương tự như các hệ thống CI xác định (nghĩa là các lần chạy không liên quan 1: 1 với các thay đổi mã và do đó bạn không chỉ tay vào một thay đổi cụ thể khi mọi thứ không thành công).

Có rất nhiều điều để nói về các bài kiểm tra ngẫu nhiên, đặc biệt là các bài kiểm tra được viết tốt, vì vậy đừng quá nhanh chóng để loại bỏ chúng!


14

Nếu bạn đang làm TDD thì tôi sẽ cho rằng dữ liệu ngẫu nhiên là một cách tiếp cận tuyệt vời. Nếu thử nghiệm của bạn được viết bằng hằng, thì bạn chỉ có thể đảm bảo mã của mình hoạt động với giá trị cụ thể. Nếu thử nghiệm của bạn ngẫu nhiên bị lỗi máy chủ xây dựng, có khả năng có vấn đề với cách thử nghiệm được viết.

Dữ liệu ngẫu nhiên sẽ giúp đảm bảo mọi tái cấu trúc trong tương lai sẽ không phụ thuộc vào hằng số ma thuật. Rốt cuộc, nếu các bài kiểm tra của bạn là tài liệu của bạn, thì không phải sự hiện diện của các hằng số có nghĩa là nó chỉ cần hoạt động cho các hằng số đó?

Tôi đang phóng đại tuy nhiên tôi thích đưa dữ liệu ngẫu nhiên vào thử nghiệm của mình như một dấu hiệu cho thấy "giá trị của biến này sẽ không ảnh hưởng đến kết quả của thử nghiệm này".

Mặc dù vậy, tôi sẽ nói rằng nếu bạn sử dụng một biến ngẫu nhiên thì hãy thử nghiệm dựa trên biến đó, thì đó là một mùi.


10

Một lợi thế cho ai đó xem xét nghiệm là dữ liệu tùy ý rõ ràng không quan trọng. Tôi đã thấy quá nhiều bài kiểm tra liên quan đến hàng tá dữ liệu và có thể khó có thể nói được điều gì cần phải theo cách đó và điều gì sẽ xảy ra theo cách đó. Ví dụ: Nếu một phương thức xác thực địa chỉ được kiểm tra với một mã zip cụ thể và tất cả các dữ liệu khác là ngẫu nhiên thì bạn có thể chắc chắn rằng mã zip là phần quan trọng duy nhất.


9
  • nếu đó là một giá trị ngẫu nhiên và thử nghiệm thất bại, chúng ta cần phải a) sửa đối tượng và b) buộc bản thân phải kiểm tra giá trị đó mỗi lần, vì vậy chúng ta biết nó hoạt động, nhưng vì ngẫu nhiên chúng ta không biết giá trị đó là gì

Nếu trường hợp thử nghiệm của bạn không ghi lại chính xác những gì nó đang thử nghiệm, có lẽ bạn cần phải mã hóa lại trường hợp thử nghiệm. Tôi luôn muốn có các bản ghi mà tôi có thể tham khảo lại cho các trường hợp thử nghiệm để tôi biết chính xác nguyên nhân gây ra lỗi đó cho dù sử dụng dữ liệu tĩnh hay ngẫu nhiên.


9

Đồng nghiệp của bạn đang thực hiện kiểm tra fuzz , mặc dù anh ta không biết về nó. Chúng đặc biệt có giá trị trong các hệ thống máy chủ.


2
nhưng đây không phải là một điều khác biệt cơ bản với các bài kiểm tra đơn vị? và thực hiện vào một thời điểm khác nhau?
endolith

1
@endolith không có luật vật lý nào buộc bạn phải chạy thử nghiệm cụ thể vào những thời điểm cụ thể
user253751

1
@immibis Nhưng có những lý do chính đáng để làm các xét nghiệm cụ thể tại thời điểm cụ thể. Bạn không chạy pin kiểm tra đơn vị mỗi khi người dùng nhấp vào nút "Ok".
endolith

5

Bạn có thể tạo một số dữ liệu ngẫu nhiên một lần (ý tôi là chính xác một lần, không phải một lần cho mỗi lần chạy thử), sau đó sử dụng nó trong tất cả các thử nghiệm sau đó?

Tôi chắc chắn có thể thấy giá trị trong việc tạo dữ liệu ngẫu nhiên để kiểm tra những trường hợp mà bạn chưa từng nghĩ đến, nhưng bạn đã đúng, có các bài kiểm tra đơn vị có thể vượt qua ngẫu nhiên hoặc thất bại là một điều tồi tệ.


5

Bạn nên tự hỏi mục tiêu của bài kiểm tra của bạn là gì.
Các bài kiểm tra đơn vị là về việc xác minh logic, dòng mã và tương tác đối tượng. Sử dụng các giá trị ngẫu nhiên cố gắng đạt được một mục tiêu khác nhau, do đó làm giảm sự tập trung và đơn giản thử nghiệm. Nó được chấp nhận vì lý do dễ đọc (tạo UUID, id, khóa, v.v.).
Cụ thể đối với các bài kiểm tra đơn vị, tôi không thể nhớ lại ngay cả khi phương pháp này đã tìm thấy thành công các vấn đề. Nhưng tôi đã thấy nhiều vấn đề xác định (trong các thử nghiệm) cố gắng thông minh với các giá trị ngẫu nhiên và chủ yếu là với các ngày ngẫu nhiên.
Thử nghiệm Fuzz là một cách tiếp cận hợp lệ cho các thử nghiệm tích hợpthử nghiệm đầu cuối .


Tôi sẽ nói thêm rằng việc sử dụng đầu vào ngẫu nhiên cho việc làm mờ là một sự thay thế kém cho việc làm mờ hướng dẫn bảo hiểm khi có thể.
gobenji

1

Nếu bạn đang sử dụng đầu vào ngẫu nhiên cho các thử nghiệm của mình, bạn cần phải ghi nhật ký đầu vào để bạn có thể xem các giá trị là gì. Bằng cách này nếu có một số trường hợp cạnh bạn gặp, bạn có thể viết bài kiểm tra để tái tạo nó. Tôi đã nghe những lý do tương tự từ những người không sử dụng đầu vào ngẫu nhiên, nhưng một khi bạn hiểu rõ về các giá trị thực tế được sử dụng cho một lần chạy thử cụ thể thì đó không phải là vấn đề.

Khái niệm dữ liệu "tùy ý" cũng rất hữu ích như một cách biểu thị một cái gì đó không quan trọng. Chúng tôi có một số thử nghiệm chấp nhận xuất hiện trong tâm trí nơi có nhiều dữ liệu nhiễu không liên quan đến thử nghiệm trong tay.


0

Tùy thuộc vào đối tượng / ứng dụng của bạn, dữ liệu ngẫu nhiên sẽ có một vị trí trong thử nghiệm tải. Tôi nghĩ quan trọng hơn sẽ là sử dụng dữ liệu kiểm tra rõ ràng các điều kiện biên của dữ liệu.


0

Chúng tôi chỉ chạy vào đây ngày hôm nay. Tôi muốn giả ngẫu nhiên (vì vậy nó sẽ trông giống như dữ liệu âm thanh nén về kích thước). Tôi TODO'd rằng tôi cũng muốn xác định . rand () khác với OSX so với Linux. Và trừ khi tôi tái gieo hạt, nó có thể thay đổi bất cứ lúc nào. Vì vậy, chúng tôi đã thay đổi nó thành xác định nhưng vẫn ngẫu nhiên: thử nghiệm có thể lặp lại, nhiều như sử dụng dữ liệu đóng hộp (nhưng được viết thuận tiện hơn).

Điều này KHÔNG được kiểm tra bởi một số lực lượng vũ phu ngẫu nhiên thông qua các đường dẫn mã. Đó là sự khác biệt: vẫn mang tính quyết định, vẫn có thể lặp lại, vẫn sử dụng dữ liệu trông giống như đầu vào thực để chạy một bộ kiểm tra thú vị về các trường hợp cạnh trong logic phức tạp. Vẫn kiểm tra đơn vị.

Điều đó vẫn đủ điều kiện là ngẫu nhiên? Hãy nói về bia. :-)


0

Tôi có thể dự tính ba giải pháp cho vấn đề dữ liệu thử nghiệm:

  • Kiểm tra với dữ liệu cố định
  • Kiểm tra với dữ liệu ngẫu nhiên
  • Tạo dữ liệu ngẫu nhiên một lần , sau đó sử dụng nó làm dữ liệu cố định của bạn

Tôi khuyên bạn nên làm tất cả các điều trên . Đó là, viết các bài kiểm tra đơn vị lặp lại với cả một số trường hợp cạnh được thực hiện bằng cách sử dụng bộ não của bạn và một số dữ liệu ngẫu nhiên mà bạn chỉ tạo một lần. Sau đó viết một loạt các thử nghiệm ngẫu nhiên mà bạn chạy cũng .

Các bài kiểm tra ngẫu nhiên không bao giờ được dự kiến ​​sẽ bắt được điều gì đó mà các bài kiểm tra lặp lại của bạn bỏ lỡ. Bạn nên cố gắng bao quát mọi thứ bằng các bài kiểm tra lặp lại và xem xét các bài kiểm tra ngẫu nhiên là một phần thưởng. Nếu họ tìm thấy thứ gì đó, đó sẽ là thứ mà bạn không thể dự đoán một cách hợp lý; một kẻ lập dị thực sự.


-2

Làm thế nào anh chàng của bạn có thể chạy thử nghiệm một lần nữa khi nó không thể xem liệu anh ta đã sửa nó chưa? Tức là anh ta mất tính lặp lại của các bài kiểm tra.

Mặc dù tôi nghĩ rằng có lẽ có một số giá trị trong việc tải một lượng dữ liệu ngẫu nhiên tại các thử nghiệm, như đã đề cập trong các câu trả lời khác, nó nằm trong tiêu đề kiểm tra tải hơn bất kỳ thứ gì khác. Đó là khá nhiều thực hành "thử nghiệm bởi hy vọng". Tôi nghĩ rằng, trong thực tế, anh chàng của bạn chỉ đơn giản là không suy nghĩ về những gì anh ta đang cố gắng kiểm tra, và bù đắp cho sự thiếu suy nghĩ đó bằng cách hy vọng sự ngẫu nhiên cuối cùng sẽ bẫy một số lỗi bí ẩn.

Vì vậy, lý lẽ tôi sẽ sử dụng với anh ta là anh ta lười biếng. Hoặc, nói cách khác, nếu anh ta không dành thời gian để hiểu những gì anh ta đang cố kiểm tra thì có lẽ anh ta không thực sự hiểu mã anh ta đang viết.


3
Có thể ghi nhật ký dữ liệu ngẫu nhiên hoặc hạt giống ngẫu nhiên để thử nghiệm có thể được sao chép.
cbp
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.