단위 테스트를 수행 할 때 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

당신은 개인적인 방법을 테스트 할 경우, 한 번 봐 가지고 PrivateObjectPrivateType에서 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.