Làm mã nội bộ nhưng có sẵn để thử nghiệm đơn vị từ các dự án khác


129

Chúng tôi đặt tất cả các bài kiểm tra đơn vị của chúng tôi trong các dự án riêng của họ. Chúng tôi thấy rằng chúng tôi phải công khai các lớp nhất định thay vì nội bộ chỉ cho các bài kiểm tra đơn vị. Có cách nào để tránh phải làm điều này. Hàm ý bộ nhớ bằng cách làm cho các lớp công khai thay vì niêm phong là gì?


Câu trả lời:


205

Nếu bạn đang sử dụng .NET, thuộc tính lắp ráp InternalsVisibleTo cho phép bạn tạo các cụm "bạn bè". Đây là các hội đồng được đặt tên cụ thể được phép truy cập các lớp nội bộ và các thành viên của hội đồng khác.

Lưu ý, điều này nên được sử dụng một cách thận trọng vì nó kết hợp chặt chẽ các hội đồng liên quan. Việc sử dụng chung cho InternalsVisibleTo là dành cho các dự án thử nghiệm đơn vị. Đây có thể không phải là một lựa chọn tốt để sử dụng trong các cụm ứng dụng thực tế của bạn, vì lý do đã nêu ở trên.

Thí dụ:

[assembly: InternalsVisibleTo("NameAssemblyYouWantToPermitAccess")]
namespace NameOfYourNameSpace
{

23
Tôi khuyên bạn nên đặt #if DEBUG xung quanh thuộc tính và sau đó kiểm tra đơn vị trong gỡ lỗi. Bằng cách đó, bạn sẽ chắc chắn rằng thuộc tính không được đặt trên mã phát hành.
steve nấu

Đây chỉ là một ý tưởng, tôi không biết .... Làm thế nào về: #if DEBUG lớp công khai IniReader #else lớp nội bộ IniReader #endif Có lẽ không được đề xuất? Tại sao?
jmelhus

4
Chà, tại sao lại giới hạn các bài kiểm tra để gỡ lỗi bản dựng?
Marco Mp

2
Ngoài ra, chỉ là một nitlog, không cần phải đặt tên cho "hội bạn" (có thể là một thông lệ tốt - ngay cả khi sở thích cá nhân của tôi nói khác, nhưng không bắt buộc).
Marco Mp

9
Không đồng ý. Nếu tôi đang xây dựng một thành phần phức tạp với API công khai rất mỏng, thì việc kiểm tra thông qua API công khai là không thực tế và không thực tế. Bạn sẽ kết thúc với một quả bóng bùn không thể nhầm lẫn. Thay vào đó, tôi cẩn thận xác định các đơn vị nội bộ và kiểm tra chúng một cách riêng biệt. Như Jeremy D. Miller đã nói khá thường xuyên: "Kiểm tra nhỏ trước khi bạn kiểm tra lớn".
Dennis Doomen

6

Nếu nó là một lớp bên trong thì nó không được sử dụng một cách cô lập. Do đó, bạn không nên thực sự kiểm tra nó ngoài việc kiểm tra một số lớp khác sử dụng đối tượng đó trong nội bộ.

Giống như bạn không nên kiểm tra các thành viên riêng của một lớp, bạn không nên kiểm tra các lớp bên trong của một DLL. Các lớp này là chi tiết triển khai của một số lớp có thể truy cập công khai, và do đó nên được thực hiện tốt thông qua các bài kiểm tra đơn vị khác.

Ý tưởng là bạn chỉ muốn kiểm tra hành vi của một lớp vì nếu bạn kiểm tra chi tiết thực hiện nội bộ thì các bài kiểm tra của bạn sẽ dễ vỡ. Bạn sẽ có thể thay đổi chi tiết triển khai của bất kỳ lớp nào mà không phá vỡ tất cả các bài kiểm tra của bạn.

Nếu bạn thấy rằng bạn thực sự cần phải kiểm tra lớp đó, thì bạn có thể muốn xem xét lại lý do tại sao lớp đó là nội bộ ngay từ đầu.


2
Chi tiết thực hiện nên được thực hiện như một phần của bài kiểm tra bao gồm. Đừng nhìn vào các biến riêng tư ... kiểm tra hành vi dự kiến. Nếu thử nghiệm là đúng .. tất cả hệ thống ống nước và hệ thống dây điện bên trong nên được kiểm tra như một phần của nó. Bỏ phiếu lên.
Gishu

69
Tôi không nhất thiết phải đồng ý với điều này vì các lớp này là "công khai" đối với các lớp khác trong DLL và chức năng của lớp nên được kiểm tra một cách độc lập
leora

27
Tôi cũng không đồng ý. Các đơn vị là các đơn vị và chúng phải được kiểm tra trong sự cô lập.
Sentinel

5
Hướng dẫn chung tuyệt vời, nhưng chúng ta đừng có giáo điều. Các thử nghiệm phục vụ hai mục đích chính: 1) Hồi quy - đảm bảo bạn không phá vỡ thứ gì đó, 2) Tăng tốc độ phát triển. Nếu tôi phải đứng lên một dịch vụ khổng lồ mỗi lần tôi muốn viết một dòng mã, tôi sẽ cản trở sự phát triển. Nếu tôi có một phần nội bộ phức tạp, tôi muốn có thể phát triển và thử nghiệm một cách cô lập. Ngược lại, tôi không muốn mọi thứ được kiểm tra riêng rẽ (do đó làm giảm giá trị kiểm tra hồi quy hoặc sao chép mã kiểm tra), nhưng một số mã chỉ ra sự cô lập. Có lẽ chìa khóa là làm cho nó một hội đồng riêng biệt.
Lee Jensen

2
OP ở đây là chính xác. Bạn đang ghép các bài kiểm tra của bạn để thực hiện nội bộ. Do đó, nhóm của bạn mãi mãi là nô lệ để sửa chữa các bài kiểm tra và mã nhạo báng khủng khiếp. Chỉ kiểm tra API công khai, là API lib được đóng gói hoặc API được hiển thị trên mạng. Tất cả các mã nên được thực hiện thông qua cửa trước. Việc triển khai thử nghiệm là lý do tại sao TDD đã chết phần lớn, đó chỉ là một Pita khổng lồ để kiểm tra từng lớp của toàn bộ ứng dụng, thay vì tập trung vào việc đảm bảo các hành vi của hệ thống. Tôi nghĩ rằng hầu hết tất cả mọi người, bao gồm cả những cuốn sách "có thẩm quyền", đã có lỗi này hoặc không làm cho nó rõ ràng.
Luke Puplett

4

cho mục đích tài liệu

cách khác, bạn có thể khởi tạo lớp bên trong bằng cách sử dụng Type.GetTypephương thức

thí dụ

//IServiceWrapper is public class which is 
//the same assembly with the internal class 
var asm = typeof(IServiceWrapper).Assembly;
//Namespace.ServiceWrapper is internal
var type = asm.GetType("Namespace.ServiceWrapper");
return (IServiceWrapper<T>)Activator
    .CreateInstance(type, new object[1] { /*constructor parameter*/ });

Đối với loại chung có quy trình khác nhau như dưới đây:

var asm = typeof(IServiceWrapper).Assembly;
//note the name Namespace.ServiceWrapper`1
//this is for calling Namespace.ServiceWrapper<>
var type = asm.GetType("Namespace.ServiceWrapper`1");
var genType = type.MakeGenericType(new Type[1] { typeof(T) });
return (IServiceWrapper<T>)Activator
     .CreateInstance(genType, new object[1] { /*constructor parameter*/});

-5

Các lớp học có thể được công khai VÀ niêm phong.

Nhưng, đừng làm vậy.

Bạn có thể tạo một công cụ để phản ánh qua các lớp bên trong và phát ra một lớp mới truy cập mọi thứ thông qua sự phản chiếu. MSTest làm điều đó.

Chỉnh sửa: Ý tôi là, nếu bạn không muốn bao gồm các công cụ kiểm tra -any- trong lắp ráp ban đầu của bạn; Điều này cũng hoạt động nếu các thành viên là riêng tư.


1
Đợi đã, cái gì? Bạn đang nói đừng làm public sealed class? Lý do của bạn cho viên ngọc đó là gì?
nghiền nát

@crush traumapony đã không đăng nhập kể từ năm 2009.
Giáo sư Falken
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.