2009-09-03 21 views
28

Trong thử nghiệm đơn vị, phương pháp thiết lập được sử dụng để tạo các đối tượng cần thiết để thử nghiệm.Kiểm tra đơn vị: Có thực tiễn tốt để có các xác nhận trong các phương pháp thiết lập không?

Trong các phương pháp thiết lập đó, tôi thích sử dụng xác nhận: Tôi biết giá trị nào tôi muốn xem trong các đối tượng và tôi muốn ghi lại kiến ​​thức đó qua xác nhận.

Trong một bài viết gần đây trên unit tests calling other unit tests đây trên stackoverflow, cảm giác chung dường như là xét nghiệm đơn vị nên không cuộc gọi thử nghiệm khác: Câu trả lời cho câu hỏi đó dường như là bạn nên cấu trúc lại thiết lập của bạn, vì vậy rằng trường hợp kiểm tra không phụ thuộc vào nhau.

Nhưng không có nhiều sự khác biệt trong "thiết lập với xác nhận" và kiểm tra đơn vị gọi các bài kiểm tra đơn vị khác.

Do đó câu hỏi của tôi: Có thực tiễn tốt để có xác nhận trong các phương pháp thiết lập không?

CHỈNH SỬA:

Câu trả lời hóa ra là: đây không phải là phương pháp hay nói chung. Nếu kết quả thiết lập cần được kiểm tra, bạn nên thêm một phương pháp thử riêng biệt với các xác nhận (câu trả lời tôi đã chọn); cho mục đích làm tài liệu, hãy xem xét sử dụng xác nhận Java.

+1

Đọc bài viết này về cách viết các bài kiểm tra đơn vị tốt: http://blog.codeville.net/2009/08/24/writing-great-unit-tests-best-and-worst-practises/ – Kane

+0

+1 cho câu hỏi thông minh – KLE

Trả lời

14

Thay vì xác nhận trong thiết lập để kiểm tra kết quả, Tôi đã sử dụng một thử nghiệm đơn giản (phương pháp thử nghiệm dọc theo các phương pháp khác, nhưng được định vị là phương pháp thử nghiệm đầu tiên).

Tôi đã thấy một số lợi thế:

  • Thiết lập giữ ngắn và tập trung, để có thể đọc.
  • Xác nhận chỉ được chạy một lần, tức là hiệu quả hơn.

Cách sử dụng và thảo luận:

Ví dụ, tôi đặt tên cho phương pháp testSetup().

Để sử dụng nó, khi tôi có một số lỗi kiểm tra trong lớp đó, tôi biết rằng nếu testSetup() có lỗi, tôi không cần phải bận tâm với các lỗi khác, tôi cần sửa lỗi này trước.

Nếu ai đó bị làm phiền bởi điều này và muốn làm cho sự phụ thuộc này rõ ràng, hàm testSetup() có thể được gọi trong phương thức setup(). Nhưng tôi không nghĩ nó quan trọng. Quan điểm của tôi là, trong JUnit, bạn đã có thể có một cái gì đó tương tự như trong phần còn lại của các bài kiểm tra của bạn:

  1. một số xét nghiệm đó kiểm tra mã địa phương,
  2. và một số xét nghiệm đó là cuộc gọi đang toàn cầu hơn, mà gián tiếp cuộc gọi cùng mã với bài kiểm tra trước đó.

Khi bạn đọc kết quả xét nghiệm mà cả hai thất bại, bạn đã có để chăm sóc phụ thuộc này mà không phải là trong các thử nghiệm, nhưng trong các mã được gọi. Trước tiên, bạn phải sửa chữa thử nghiệm đơn giản và sau đó chạy lại kiểm tra toàn cầu để xem thử nghiệm đó có bị lỗi hay không. Đây là lý do tại sao tôi không bị làm phiền bởi sự phụ thuộc ngầm mà tôi đã giải thích trước đây.

+2

Sáng nay tôi đã thảo luận câu hỏi với một đồng nghiệp và chúng tôi đã đưa ra giải pháp này. Thật tốt khi biết rằng bạn có kinh nghiệm tích cực với nó! – avandeursen

+0

@Kaka Cảm ơn bạn đã bình luận quan tâm của bạn, và cho việc tăng cường phản hồi của bạn cung cấp. :-) – KLE

+0

@KLE: đây là một chiến lược thú vị và hiệu quả. Nhưng tôi tự hỏi làm thế nào để bạn chắc chắn rằng 'testSetup() 'được thực hiện khi bạn thực hiện các thử nghiệm với một bộ lọc (ví dụ:' --gtest_filter'). – Sampath

9

Các trường hợp khác nhau; Tôi không thấy sự giống nhau.

Phương pháp thiết lập phải chứa mã phổ biến (lý tưởng) tất cả các thử nghiệm trong lịch thi đấu. Như vậy, không có gì sai khi đưa các xác nhận vào một phương thức thiết lập thử nghiệm nếu một số thứ nhất định phải đúng trước khi phần còn lại của mã thử nghiệm thực thi. Thiết lập là phần mở rộng của thử nghiệm; nó là một phần của thử nghiệm nói chung. Nếu các chuyến đi khẳng định, mọi người sẽ khám phá điều kiện tiên quyết nào không thành công.

Mặt khác, nếu quá trình thiết lập đủ phức tạp khiến bạn cảm thấy cần phải khẳng định nó là chính xác, đó có thể là dấu hiệu cảnh báo. Hơn nữa, nếu tất cả các bài kiểm tra không yêu cầu đầu ra đầy đủ của thiết lập, thì đó là dấu hiệu cho thấy lịch thi đấu có sự gắn kết kém và phải được phân chia dựa trên các kịch bản và/hoặc được cấu trúc lại.

Một phần là do điều này mà tôi có xu hướng tránh xa việc sử dụng các phương pháp Thiết lập. Nếu có thể, tôi sử dụng các phương pháp nhà máy riêng tư hoặc tương tự để thiết lập mọi thứ. Nó làm cho bài kiểm tra dễ đọc hơn và tránh nhầm lẫn. Đôi khi điều này là không thực tế (ví dụ: làm việc với các lớp kết hợp chặt chẽ và/hoặc khi viết các bài kiểm tra tích hợp), nhưng đối với phần lớn các bài kiểm tra của tôi, nó thực hiện công việc.

9

Có các xác nhận trong phương pháp Thiết lập/TearDown không được khuyến khích. Nó làm cho bài kiểm tra ít có thể đọc được nếu người dùng cần "hiểu" rằng một số logic thử nghiệm không có trong phương pháp thử nghiệm. Có những lúc bạn không có lựa chọn nào khác ngoài việc sử dụng các phương pháp thiết lập/rách cho một thứ khác ngoài những gì họ dự định.

Có vấn đề lớn hơn trong câu hỏi này: một thử nghiệm gọi một thử nghiệm khác, đó là một mùi cho một số vấn đề trong các thử nghiệm của bạn. Mỗi thử nghiệm nên kiểm tra một khía cạnh cụ thể của mã của bạn và chỉ nên có một hoặc hai xác nhận trong đó, vì vậy nếu thử nghiệm của bạn gọi một thử nghiệm khác, bạn có thể thử nghiệm quá nhiều thứ trong thử nghiệm đó. Để biết thêm thông tin, hãy đọc: Unit Testing: One Test, One Assertion - Why It Works

+0

Thú vị trỏ đến một thử nghiệm/một khẳng định, và tôi thích viết lại của bạn thành "một hoặc hai". – avandeursen

+1

URL đã bị hỏng. Đây là bản cập nhật. [Kiểm tra đơn vị: Một thử nghiệm, một xác nhận - Tại sao nó hoạt động] (http://blog.astrumfutura.com/2009/02/unit-testing-one-test-one-assertion-why-it-works/) – James

3

Làm theo các quyết định về trái tim/chớp mắt của bạn. Các xác nhận trong một phương thức Thiết lập có thể có ý định tài liệu; có thể đọc được.Vì vậy, cá nhân tôi sẽ trở lại bạn về điều này.
Khác với thử nghiệm gọi các xét nghiệm khác - điều đó là xấu. Không cô lập thử nghiệm. Một thử nghiệm không nên ảnh hưởng đến kết quả của một thử nghiệm khác.

Mặc dù đây không phải là trường hợp sử dụng tự do, đôi khi tôi sử dụng Asserts bên trong phương thức Thiết lập để tôi có thể biết nếu thiết lập thử nghiệm không diễn ra như tôi dự định; thường khi tôi giao dịch với các thành phần mà tôi không tự viết. Lỗi xác nhận có nội dung 'Thiết lập không thành công!' trong tab lỗi - nhanh chóng giúp tôi vùng trên mã thiết lập thay vì phải xem xét một loạt các thử nghiệm không thành công.

Lỗi thiết lập thường sẽ khiến tất cả các thử nghiệm trong vật cố đó thất bại - đó là mùi mà mũi của bạn sẽ sớm được lấy. 'Tất cả các kiểm tra thất bại thường ngụ ý Thiết lập đã bị phá vỡ' Vì vậy, các xác nhận không phải lúc nào cũng cần thiết. Điều đó nói thực tế, hãy nhìn vào bối cảnh cụ thể của bạn và 'Thêm vào hương vị'.

+0

Tốt điểm - Cảm ơn. Điều này có nghĩa là sử dụng JUnit khẳng định cho hai mục đích khác nhau: (1) ý định tài liệu; (2) Kiểm tra kết quả như mong đợi. – avandeursen

3

Tôi sử dụng Java asserts, chứ không phải JUnit, trong trường hợp một cái gì đó như thế này là cần thiết. ví dụ. khi bạn sử dụng một số lớp tiện ích khác để thiết lập dữ liệu thử nghiệm .:

byte[] pkt = pktFactory.makePacket(TIME, 12, "23, F2"); 
assert pkt.length == 15; 

không có ngụ ý 'hệ thống không phải là trong tình trạng thậm chí thử để chạy thử nghiệm này.

+0

Tôi thích ý tưởng. Điều này đặt ra câu hỏi chung cho dù đó là thực hành tốt để kết hợp các phương thức Java asserts và JUnit Assert, nhưng tôi thích lý do của bạn. – avandeursen

Các vấn đề liên quan