단위 테스트를 수행 할 때 C # "내부"액세스 수정 자


469

나는 단위 테스트에 익숙하지 않아서 더 많은 '내부'액세스 수정자를 사용하기 시작하는지 알아 내려고 노력 중입니다. 'internal'을 사용하고 어셈블리 변수 'InternalsVisibleTo'를 설정하면 테스트 프로젝트에서 public을 선언하고 싶지 않은 함수를 테스트 할 수 있습니다. 이것은 적어도 각 프로젝트 (해야합니까?)에는 자체 테스트 프로젝트가 있기 때문에 항상 '내부'를 사용해야한다고 생각합니다. 내가 왜 이것을하지 말아야하는지 이유를 말해 줄 수 있습니까? '비공개'는 언제 사용해야합니까?


1
언급 할 가치가있는 경우- System.Diagnostics.Debug.Assert()메소드 자체를 사용하여 내부 메소드를 단위 테스트 할 필요가없는 경우가 종종 있습니다.
— Mike Marynowski 2016 년

답변:


1195

내부 클래스를 테스트해야하며 어셈블 속성이 있습니다.

using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("MyTests")]

이를 프로젝트 정보 파일에 추가하십시오 (예 :) Properties\AssemblyInfo.cs.


70
테스트중인 프로젝트에 추가하십시오 (예 : Properties \ AssemblyInfo.cs). "MyTests"는 테스트 어셈블리입니다.
— EricSchaefer

86
이것은 실제로 받아 들여지는 대답이어야합니다. 나는 너희들에 대해 모른다. 그러나 테스트가 코드에서 "너무 멀다"고 테스트 할 때 나는 긴장하는 경향이있다. 나는로 표시된 것을 테스트하지 않으려 고 private하지만 너무 많은 private것들이 internal추출하기 위해 고군분투 하는 클래스를 가리킬 수 있습니다. TDD 또는 TDD가없는 경우 동일한 코드를 테스트하는 테스트가 거의없는 것보다 많은 코드를 테스트하는 테스트를 더 선호합니다. 그리고 internal물건 을 테스트 하지 않는 것이 좋은 비율을 달성하는 데 정확히 도움이되지는 않습니다.
— sm

7
좋은있다 토론 사이의 의미 적 차이에 대한 @DerickBailey 댄 타오 사이에 진행 내부 와 개인 및 테스트 할 필요가 내부 구성 요소는. 읽을만한 가치가 있습니다.
— Kris McGinnes

31
에 포장하고 #if DEBUG, #endif블록은 디버그 빌드에서만이 옵션을 사용합니다.
— 실제 에드워드 컬렌

17
이것이 정답입니다. 공용 메소드 만 단위 테스트되어야한다고 말하는 모든 대답에는 단위 테스트의 요점이 누락되어 변명합니다. 기능 테스트는 블랙 박스 지향입니다. 단위 테스트는 화이트 박스 중심입니다. 퍼블릭 API뿐만 아니라 기능의 "단위"를 테스트해야합니다.
— Gunnar

127

당신은 개인적인 방법을 테스트 할 경우, 한 번 봐 가지고 PrivateObject와 PrivateType에서 Microsoft.VisualStudio.TestTools.UnitTesting네임 스페이스를. 필요한 리플렉션 코드 주위에 래퍼를 쉽게 사용할 수 있습니다.

문서 도구 : PrivateType , PrivateObject

VS2017 및 2019의 경우 MSTest를 다운로드하여 찾을 수 있습니다.


15
투표 할 때 의견을 남겨주십시오. 감사.
— 브라이언 라스무센

35
이 답변을 멍청하게 투표합니다. 새로운 솔루션과 이전에 언급되지 않은 정말 좋은 솔루션을 가리 킵니다.
— Ignacio Soler Garcia

분명히 .net2.0 이상을 대상으로하는 앱에 TestFramework를 사용하는 데 문제가 있습니다. github.com/Microsoft/testfx/issues/366
— Johnny Wu

41

Eric의 답변에 추가하여 csproj파일 에서이를 구성 할 수도 있습니다 .

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

또는 테스트 할 프로젝트 당 하나의 테스트 프로젝트가있는 경우 Directory.Build.props파일 에서 다음과 같은 작업을 수행 할 수 있습니다.

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

참조 : https://stackoverflow.com/a/49978185/1678053
예 : https://github.com/gldraphael/evlog/blob/master/Directory.Build.props#L5-L12


2
이것이 최고의 답변이되어야합니다. .net이 어셈블리 정보에서 멀어지고 기능을 csproj 정의로 옮길 때 다른 모든 답변은 매우 구식입니다.
— mBrice1024

12

기본적으로 비공개를 사용하십시오. 멤버가 해당 유형 이상으로 노출되지 않아야하는 경우 같은 유형의 프로젝트 내에서도 해당 유형 이상으로 노출되어서는 안됩니다. 이렇게하면 물건을보다 안전하고 깔끔하게 유지할 수 있습니다. 객체를 사용할 때 사용할 수있는 방법이 더 명확합니다.

그러나 자연스럽게 개인 메서드를 테스트 목적으로 내부적으로 만드는 것이 합리적이라고 생각합니다. 리팩토링에 익숙하지 않은 리플렉션을 사용하는 것이 좋습니다.

고려해야 할 한 가지는 "ForTest"접미사 일 수 있습니다.

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

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

그런 다음 동일한 프로젝트 내에서 클래스를 사용할 때 실제로는이 방법을 사용하지 않아야한다는 것이 명백합니다 (현재와 미래). 테스트 목적으로 만 존재합니다. 이것은 약간 해키이며, 내가하는 일이 아니지만 적어도 고려할 가치가 있습니다.


2
분석법이 내부 분석법 인 경우 시험 조립체에서의 사용을 방해하지 않습니까?
— 랄프 실링

7
때로는 ForTest접근 방식을 사용 하지만 항상 프로덕션 비즈니스 로직 측면에서 실제 가치를 제공하지 않는 코드를 추가하는 것은 추악합니다. 일반적으로 디자인이 다소 불행하기 때문에이 방법을 사용해야한다는 것을 알았습니다 (예 : 테스트간에 싱글 톤 인스턴스를 재설정해야 함)
— ChrisWue

1
이 해킹에 유혹을 느꼈습니다.이 해킹과 단순히 개인이 아닌 내부 클래스를 만드는 것의 차이점은 무엇입니까? 글쎄, 적어도 컴파일 조건부에서는. 그러면 정말 지저분 해집니다.
— CAD bloke

6
@CADbloke : 메소드를 개인용이 아닌 내부 용으로 만드는 것을 의미 합니까? 차이점은 당신이 정말로 사적인 것을 원한다는 것이 분명하다는 것 입니다. 메소드를 호출하는 프로덕션 코드베이스 내의 모든 코드 ForTest는 분명히 잘못된 반면, 메소드를 내부로 만들면 사용하는 것이 좋습니다.
— Jon Skeet 10

2
@CADbloke : 부분 클래스 IMO를 사용하는 것과 동일한 파일에서 릴리스 빌드 내 개별 메소드를 쉽게 제외 할 수 있습니다. 당신이 있다면 어떻게 그렇게, 당신이 나에게 나쁜 생각처럼 들리 당신의 릴리스 빌드에 대해 테스트를 실행하지 않는 것이 좋습니다.
— Jon Skeet 10

11

개인도 사용할 수 있으며 리플렉션을 사용하여 개인 메서드를 호출 할 수 있습니다. Visual Studio Team Suite를 사용하는 경우 개인 메서드를 호출하는 프록시를 생성하는 멋진 기능이 있습니다. 다음은 개인 및 보호 된 메소드를 단위 테스트하기 위해 직접 작업을 수행 할 수있는 방법을 보여주는 코드 프로젝트 기사입니다.

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

어떤 액세스 수정자를 사용해야하는지에 대한 일반적인 경험 규칙은 필요에 따라 비공개로 시작하고 이관합니다. 이렇게하면 클래스의 내부 세부 정보를 거의 필요로하지 않고 구현 세부 정보를 숨겨두는 데 도움이됩니다.


3

나는 사용 Dotnet 3.1.101하고 있으며 .csproj나를 위해 일한 추가 사항은 다음과 같습니다.

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

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

이것이 누군가를 도울 수 있기를 바랍니다!


1
어셈블리 정보를 명시 적으로 생성하는 것이 마침내 나에게도 효과적이었습니다. 이것을 게시 해 주셔서 감사합니다!
— thevioletsaber
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.