Công cụ sửa đổi truy cập nội bộ C # ăn khi thực hiện kiểm tra đơn vị


469

Tôi mới tham gia thử nghiệm đơn vị và tôi đang cố gắng tìm hiểu xem tôi có nên bắt đầu sử dụng nhiều công cụ sửa đổi truy cập 'nội bộ' hay không. Tôi biết rằng nếu chúng tôi sử dụng 'nội bộ' và đặt biến lắp ráp 'InternalsVisibleTo', chúng tôi có thể kiểm tra các chức năng mà chúng tôi không muốn tuyên bố công khai từ dự án thử nghiệm. Điều này khiến tôi nghĩ rằng tôi chỉ nên luôn sử dụng 'nội bộ' vì ít nhất mỗi dự án (nên?) Có dự án thử nghiệm riêng. Các bạn có thể cho tôi biết một lý do tại sao tôi không nên làm điều này? Khi nào tôi nên sử dụng 'riêng tư'?


1
Đáng nói - bạn thường có thể tránh sự cần thiết phải kiểm tra đơn vị phương thức nội bộ của mình bằng cách sử dụng System.Diagnostics.Debug.Assert()chính các phương thức đó.
Mike Marynowski

Câu trả lời:


1195

Các lớp bên trong cần phải được kiểm tra và có một thuộc tính lắp ráp:

using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("MyTests")]

Thêm phần này vào tệp thông tin dự án, vd Properties\AssemblyInfo.cs.


70
Thêm nó vào dự án đang thử nghiệm (ví dụ: trong Properties \ HộiInfo.cs). "MyTests" sẽ là hội đồng thử nghiệm.
EricSchaefer

86
Đây thực sự nên là câu trả lời được chấp nhận. Tôi không biết về các bạn, nhưng khi các bài kiểm tra "quá xa" so với mã họ đang kiểm tra, tôi có xu hướng lo lắng. Tôi là tất cả để tránh kiểm tra bất cứ điều gì được đánh dấu private, nhưng quá nhiều privatethứ rất có thể chỉ ra một internallớp đang đấu tranh để được trích xuất. TDD hoặc không có TDD, tôi thích có nhiều bài kiểm tra kiểm tra nhiều mã hơn là có ít bài kiểm tra thực hiện cùng một lượng mã. Và tránh để kiểm tra internalcông cụ không chính xác giúp đạt được tỷ lệ tốt.
sm

7
Có một cuộc thảo luận tuyệt vời đang diễn ra giữa @DerickBailey và Dan Tao liên quan đến sự khác biệt về ngữ nghĩa giữa nội bộriêng tư và nhu cầu kiểm tra các thành phần nội bộ . Rất đáng để đọc.
Kris McGinnes

31
Gói trong và #if DEBUG, #endifkhối sẽ chỉ cho phép tùy chọn này trong các bản dựng gỡ lỗi.
Real Edward Cullen

17
Đây là câu trả lời chính xác. Bất kỳ câu trả lời nào nói rằng chỉ có các phương thức công khai nên được kiểm tra đơn vị là thiếu điểm kiểm tra đơn vị và đưa ra lý do. Kiểm tra chức năng là hộp đen định hướng. Kiểm tra đơn vị được định hướng hộp trắng. Họ nên thử nghiệm "đơn vị" chức năng, không chỉ các API công khai.
Gunnar

127

Nếu bạn muốn thử nghiệm các phương thức riêng tư, hãy xem PrivateObjectPrivateTypetrong Microsoft.VisualStudio.TestTools.UnitTestingkhông gian tên. Họ cung cấp các hàm bao dễ sử dụng xung quanh mã phản chiếu cần thiết.

Documents: PrivateType , PrivateObject

Đối với VS2017 & 2019, bạn có thể tìm thấy những thứ này bằng cách tải xuống nuget MSTest.TestFramework


15
Khi bỏ phiếu xin vui lòng để lại nhận xét. Cảm ơn.
Brian Rasmussen

35
Thật ngu ngốc khi bỏ phiếu xuống câu trả lời này. Nó chỉ ra một giải pháp mới và một giải pháp thực sự tốt chưa được đề cập trước đây.
Ignacio Soler Garcia

Rõ ràng, có một số vấn đề khi sử dụng TestFramework để nhắm mục tiêu ứng dụng .net2.0 hoặc mới hơn: github.com/Microsoft/testfx/issues/366
Johnny Wu

41

Thêm vào câu trả lời của Eric, bạn cũng có thể định cấu hình câu hỏi này trong csprojtệp:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
      <_Parameter1>MyTests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Hoặc nếu bạn có một dự án thử nghiệm cho mỗi dự án sẽ được thử nghiệm, bạn có thể làm một cái gì đó như thế này trong Directory.Build.propstệp của mình :

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
      <_Parameter1>$(MSBuildProjectName).Test</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Xem: https://stackoverflow.com/a/49978185/1678053
Ví dụ: https://github.com/gldraphael/evlog/blob/master/Directory.Build.props#L5-L12


2
Đây phải là câu trả lời hàng đầu imo. Tất cả các câu trả lời khác đều rất lỗi thời vì .net đang rời khỏi thông tin lắp ráp và chuyển chức năng sang các định nghĩa csproj.
mBrice1024

12

Tiếp tục sử dụng riêng tư theo mặc định. Nếu một thành viên không nên tiếp xúc ngoài loại đó, thì không nên tiếp xúc với loại đó, ngay cả trong cùng một dự án. Điều này giúp mọi thứ an toàn và gọn gàng hơn - khi bạn đang sử dụng đối tượng, sẽ rõ ràng hơn phương pháp nào bạn có thể sử dụng.

Phải nói rằng, đôi khi tôi nghĩ rằng việc đưa các phương thức riêng tư vào mục đích thử nghiệm là hợp lý. Tôi thích điều đó hơn là sử dụng sự phản chiếu, đó là tái cấu trúc - không thân thiện.

Một điều cần xem xét có thể là hậu tố "ForTest":

internal void DoThisForTest(string name)
{
    DoThis(name);
}

private void DoThis(string name)
{
    // Real implementation
}

Sau đó, khi bạn đang sử dụng lớp trong cùng một dự án, rõ ràng (hiện tại và trong tương lai) rằng bạn không thực sự nên sử dụng phương pháp này - nó chỉ dành cho mục đích thử nghiệm. Đây là một chút hack, và không phải là điều tôi tự làm, nhưng ít nhất nó đáng để xem xét.


2
Nếu phương thức là nội bộ thì điều này không loại trừ việc sử dụng nó khỏi hội đồng thử nghiệm?
Ralph Shillington

7
Thỉnh thoảng tôi sử dụng ForTestcách tiếp cận nhưng tôi luôn thấy nó thật xấu xí (thêm mã không cung cấp giá trị thực tế về mặt logic kinh doanh sản xuất). Thông thường tôi thấy tôi phải sử dụng cách tiếp cận vì thiết kế là điều không may (nghĩa là phải đặt lại các trường hợp đơn lẻ giữa các lần kiểm tra)
ChrisWue

1
Bị cám dỗ để hạ thấp điều này - sự khác biệt giữa hack này và chỉ đơn giản là làm cho lớp bên trong thay vì riêng tư? Vâng, ít nhất là với các điều kiện biên soạn. Sau đó, nó thực sự lộn xộn.
CAD bloke

6
@CADbloke: Bạn có nghĩa là làm cho phương thức bên trong chứ không phải riêng tư? Sự khác biệt là rõ ràng là bạn thực sự muốn nó là riêng tư. Bất kỳ mã trong codebase sản xuất của bạn trong đó kêu gọi một phương thức với ForTestrõ ràng là sai, trong khi nếu bạn chỉ cần thực hiện phương pháp nội bộ có vẻ như đó là tốt để sử dụng.
Jon Skeet

2
@CADbloke: Bạn có thể loại trừ các phương thức riêng lẻ trong một bản phát hành dễ dàng trong cùng một tệp như sử dụng các lớp một phần, IMO. Và nếu bạn làm điều đó, điều đó cho thấy rằng bạn không chạy thử nghiệm đối với bản phát hành của bạn, điều này nghe có vẻ là một ý tưởng tồi đối với tôi.
Jon Skeet

11

Bạn cũng có thể sử dụng riêng tư và bạn có thể gọi các phương thức riêng tư với sự phản chiếu. Nếu bạn đang sử dụng Visual Studio Team Suite, nó có một số chức năng tuyệt vời sẽ tạo proxy để gọi các phương thức riêng tư cho bạn. Đây là một bài viết dự án mã trình bày cách bạn có thể tự thực hiện công việc để kiểm tra các phương thức riêng tư và được bảo vệ:

http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx

Về mặt mà bạn nên sử dụng công cụ sửa đổi truy cập, quy tắc chung của tôi là bắt đầu với chế độ riêng tư và leo thang khi cần thiết. Bằng cách đó, bạn sẽ tiết lộ rất ít các chi tiết nội bộ của lớp của bạn khi thực sự cần thiết và nó giúp giữ các chi tiết triển khai được ẩn, như chúng nên có.


3

Tôi đang sử dụng Dotnet 3.1.101và các .csprojbổ sung có hiệu quả với tôi là:

<PropertyGroup>
  <!-- Explicitly generate Assembly Info -->
  <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
</PropertyGroup>

<ItemGroup>
  <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
  <_Parameter1>MyProject.Tests</_Parameter1>
  </AssemblyAttribute>
</ItemGroup>

Hy vọng điều này sẽ giúp ai đó ngoài kia!


1
Việc bổ sung thông tin lắp ráp rõ ràng là điều cuối cùng cũng làm cho nó hoạt động với tôi. Cảm ơn vì đã đăng tải điều này!
thevioletsaber
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.