Bạn có muốn biến nội dung riêng tư thành nội bộ / công khai để kiểm tra hoặc sử dụng một số loại hack như PrivateObject không?


26

Tôi là một người mới bắt đầu thử nghiệm mã, và là một assertcon điếm trước đây. Một điều khiến tôi lo lắng khi thử nghiệm đơn vị là thường yêu cầu bạn tạo public(hoặc ít nhất internal) các trường có thể là privatekhác, để hủy readonlybỏ chúng, tạo privatephương thức protected virtualthay thế, v.v ...

Gần đây tôi đã phát hiện ra rằng bạn có thể tránh điều này bằng cách sử dụng những thứ như lớp PrivateObject để tích lũy bất cứ thứ gì trong một đối tượng thông qua sự phản chiếu. Nhưng điều này làm cho các bài kiểm tra của bạn ít được bảo trì hơn (mọi thứ sẽ thất bại khi thực hiện thay vì thời gian biên dịch, nó sẽ bị phá vỡ bởi một đổi tên đơn giản, khó gỡ lỗi hơn ...). Ý kiến ​​của bạn như thế nào ? Các thực tiễn tốt nhất trong thử nghiệm đơn vị liên quan đến hạn chế truy cập là gì?

chỉnh sửa: xem xét ví dụ rằng bạn có một lớp với bộ đệm trong một tệp trên đĩa và trong các bài kiểm tra của bạn, bạn muốn ghi vào bộ nhớ thay thế.


2
Những người trăn chỉ có công khai. Họ đang hạnh phúc. Sao phải lo lắng? Tại sao không công khai mọi thứ?
S.Lott

12
Bởi vì đó là xa thực tiễn tốt nhất trong phần lớn các ngôn ngữ hàng đầu. Câu trả lời thực sự là sử dụng các giao diện tốt và như vậy để bạn có thể sử dụng các đối tượng giả để thực hiện kiểm tra.
Giàn khoan

2
@Rig: Python không phải là ngôn ngữ hàng đầu? Hấp dẫn.
S.Lott

7
"Nó khác xa với các thực tiễn tốt nhất trong phần lớn các ngôn ngữ hàng đầu" không ngụ ý một cách logic (hoặc thậm chí ám chỉ rằng "Python không phải là ngôn ngữ hàng đầu".
Mike Nakis

1
Chính xác, nó là ngôn ngữ hàng đầu nhưng hầu hết các ngôn ngữ hàng đầu không phải là Python và xác nhận cài đặt phạm vi phù hợp. Tôi đứng trước tuyên bố của tôi. Có các mẫu được thiết kế để làm cho phần mềm có thể kiểm tra cao trong khi vẫn đảm bảo các biến duy trì phạm vi. Ngay cả các lập trình viên Python cũng có xu hướng mô phỏng phạm vi với các tiền tố từ những gì tôi đã thấy.
Giàn khoan

Câu trả lời:


36

Bạn không bao giờ phải

tạo public(hoặc ít nhất internal) các trường có thể là privatekhác, để hủy readonlybỏ chúng, tạo privatephương thức protected virtualthay thế

Đặc biệt là không đọc một lĩnh vực có thể làm cho một đối tượng bất biến có thể biến đổi, và đó sẽ là một thảm họa.

Các thử nghiệm của bạn nên coi các đối tượng của bạn là hộp đen ( Wikipedia ), có nghĩa là chúng chỉ nên liên quan đến giao diện chung của các đối tượng, chứ không phải với các chi tiết về việc triển khai chúng.

Nếu một đối tượng không thể được kiểm tra đầy đủ bằng giao diện chung của nó, thì bạn cần tìm cách cung cấp các tiện ích mở rộng chính thức và hữu ích cho giao diện của nó để tạo điều kiện cho việc kiểm tra. Ví dụ, một hệ thống đăng ký chỉ có một cặp phương thức Đăng ký / Deregister có thể sẽ được hưởng lợi từ phương thức IsRegistered ngay cả khi không cần thiết cho ứng dụng trong tay; Tuy nhiên, đây là một phần mở rộng chính thức và hữu ích cho giao diện, và nó sẽ, ngẫu nhiên, phù hợp với thử nghiệm.

Điều quan trọng là việc thay đổi việc thực hiện đối tượng không nên yêu cầu bạn thay đổi bài kiểm tra đơn vị. Về lý thuyết, bạn sẽ có thể viết bài kiểm tra đơn vị một lần, sau đó yêu cầu nhiều lập trình viên viết mã nhiều triển khai hoàn toàn khác nhau của đối tượng được kiểm tra để làm việc với bài kiểm tra đơn vị.


2
Chính xác! Nếu bạn không thể kiểm tra đơn vị mà không có sự phản chiếu hoặc hack, thì có lẽ bạn đã có lỗi trong API hoặc thiết kế của mình.
Falcon

Bạn đang nói rằng làm cho privatecác phương pháp protected virtualđể giúp chế nhạo trong các bài kiểm tra được coi là thực hành xấu?
Robula

1
@Robula Trong cuốn sách của tôi, vâng. Tôi thậm chí không viết các bài kiểm tra của mình trong cùng một gói với mã sản xuất, vì tôi không thể sử dụng để có thể truy cập các thành viên ngoài công lập. Tôi cũng không sử dụng giả. Tất nhiên, nếu bạn phải sử dụng giả, thì bạn sẽ phải làm mọi cách để tạo điều kiện cho việc chế giễu, vì vậy ảo được bảo vệ có thể là một sự thỏa hiệp thực tế trong nhiều tình huống. Nhưng lý tưởng là một thiết kế không cần giả, chỉ có triển khai thay thế và thử nghiệm lý tưởng là thử nghiệm hộp đen, không phải thử nghiệm hộp trắng, vì vậy mọi thứ được thử nghiệm trong tích hợp, không có giả.
Mike Nakis

13

Trong C #, bạn có thể sử dụng InternalsVisibleToAttributeđể cho phép lắp ráp thử nghiệm của mình để xem internalcác lớp trong cụm mà bạn đang thử nghiệm. Có vẻ như bạn đã biết điều này.

Trong hầu hết các trường hợp, tôi chỉ muốn thử nghiệm API công khai của tổ hợp. Trong trường hợp tôi muốn thực hiện kiểm thử hộp trắng của một số đơn vị, tôi di chuyển mã đến một internallớp và biến nó thành một publicphương thức của lớp đó. Sau đó tôi có thể mã một bài kiểm tra đơn vị cho lớp đó.

Điều này cho vay chính nó để tiêm phụ thuộc và mô hình chiến lược. Bạn có thể trừu tượng hóa phương thức vào một giao diện, đưa giao diện vào hàm tạo của đối tượng cha mẹ của bạn và chỉ cần kiểm tra xem các đại biểu cha mẹ có thích hợp không. Sau đó, bạn có thể kiểm tra xem đối tượng con có hành vi phù hợp không. Điều này làm cho mọi thứ nhiều mô-đun hơn.


8

Theo kinh nghiệm của tôi, tốt nhất là không để lộ nội bộ của lớp bạn đặc biệt cho bài kiểm tra. Mặc dù điều này có thể xuất hiện để làm cho bài kiểm tra dễ viết hơn. Bài kiểm tra là khách hàng đầu tiên của lớp của bạn, vì vậy nếu khó kiểm tra lớp của bạn thông qua giao diện chung, có lẽ cũng khó sử dụng lớp của bạn ở những nơi khác.

Lớp dễ dàng kiểm tra thông qua API công khai của nó là phản hồi về mức độ dễ sử dụng của lớp. Hãy nghĩ về các bài kiểm tra một phần như một cách để tạo nguyên mẫu cho việc sử dụng lớp của bạn.

Cố gắng xem xét lý do tại sao bài kiểm tra của bạn cần cảm nhận điều gì đó về lớp không có sẵn thông qua API công khai. Có lẽ lớp học của bạn đang làm quá nhiều và cần phải phân tách thành một nhóm các lớp hợp tác thay thế? Sau đó, bạn có thể chế giễu một số lớp cộng tác để cảm nhận những gì lớp đang kiểm tra đang làm.

Cố gắng áp dụng hiệu trưởng đảo ngược phụ thuộc và giới thiệu giao diện giữa các lớp mà bạn có thể giả định trong các bài kiểm tra của mình. Bạn có thể cung cấp cho các cộng tác viên để thử nghiệm bằng cách sử dụng đảo ngược quyền kiểm soát .

Ngoài ra, hãy xem xét áp dụng hiệu trưởng "nói không hỏi" để giúp cấu trúc giao diện lớp của bạn theo cách thức mạnh mẽ, được kết nối lỏng lẻo, nơi thông tin phù hợp được phơi bày và phần còn lại bị ẩn.


6

Cá nhân tôi thích để lại mã mà tôi đang kiểm tra một cách thuần túy nhất có thể và nếu mã kiểm tra cần hack (và trong con trỏ khó chịu C ++, v.v.) tôi rất vui khi làm điều đó.



1
Tôi đồng ý, đây là cách để làm điều đó. Giữ sự xấu xí trong mã kiểm tra, nơi nó không thể làm tổn thương bất cứ điều gì.
Alan Delimon

@AlanDelimon Có thể nó không làm tổn thương tâm trí của các lập trình viên bảo trì tiếp theo?
flamingpenguin

1
@flamingpenguin mã xấu có thể làm tổn thương lập trình viên ở bất cứ đâu; nhưng mã kiểm tra xấu xí sẽ có thể gây hại ít hơn vì nó sẽ chỉ ảnh hưởng đến những người sửa đổi lớp và không chỉ những người đơn giản tiêu thụ nó.
Dan Neely

2
@flamingpenguin Có thể, nhưng nếu bạn phải đặt mã xấu ở đâu đó, thì đó cũng có thể là một bài kiểm tra đơn vị trong đó ít có khả năng cần sửa đổi và là một phần của ứng dụng.
Alan Delimon

5

Khả năng hiển thị mã của bạn không liên quan gì đến các bài kiểm tra đơn vị của bạn!

Bạn đặt phương thức của mình ở chế độ riêng tư không nhằm mục đích che giấu chúng khỏi thử nghiệm và bạn không đặt chúng ở chế độ công khai để thử nghiệm, phải không? Đây là sự bổ sung của bạn rất cần thiết ở đây, không phải các bài kiểm tra - những máy chủ đó là bằng chứng về mã của bạn, nhưng chúng không phải là mã của bạn .

Có rất nhiều cách để cho phép truy cập vào các phương thức và thuộc tính ẩn (riêng tư hoặc nội bộ). Nhiều khung kiểm tra và IDE (ví dụ: Visual Studio) hỗ trợ bạn ở đây bằng cách tạo mọi thứ cần thiết cho quyền truy cập, bạn chỉ phải tạo ra các trường hợp thử nghiệm của mình. Vậy, tại sao phải lo lắng? Tốt hơn giữ mã của bạn sạch sẽ và gọn gàng.

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.