내부적으로 코드를 작성하지만 다른 프로젝트에서 단위 테스트에 사용 가능


129

우리는 모든 단위 테스트를 자체 프로젝트에 넣었습니다. 우리는 단위 테스트를 위해 내부 대신 특정 클래스를 공개해야한다는 것을 알았습니다. 어쨌든 이것을 피할 수 있습니까? 봉인 대신 클래스를 공개함으로써 메모리에 미치는 영향은 무엇입니까?


답변:


205

.NET을 사용하는 경우 InternalsVisibleTo 어셈블리 속성을 사용하면 "친구"어셈블리를 만들 수 있습니다. 이들은 내부 클래스와 다른 어셈블리의 멤버에 액세스 할 수있는 강력한 이름의 어셈블리입니다.

이것은 관련된 어셈블리를 단단히 결합하므로 신중하게 사용해야합니다. InternalsVisibleTo의 일반적인 용도는 단위 테스트 프로젝트입니다. 위에서 언급 한 이유로 실제 응용 프로그램 어셈블리에 사용하기에 적합하지 않을 수 있습니다.

예:

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

23
속성 주위에 #if DEBUG를 넣은 다음 디버그에서 단위 테스트를 수행하는 것이 좋습니다. 그렇게하면 릴리스 코드에서 속성이 설정되지 않았는지 확인할 수 있습니다.
Steve 요리

이것은 단지 아이디어 일뿐입니다 .... 어떻습니까 : #if DEBUG public class IniReader #else 내부 클래스 IniReader #endif 아마 권장되지 않습니까? 왜?
jmelhus

4
글쎄, 왜 빌드를 디버그하기 위해 테스트를 제한 하는가?
Marco Mp

2
또한, 엄선 된 이름만으로 "친구"어셈블리의 이름을 강하게 지정할 필요가 없습니다 (개인 취향에 따라 다르게 말하지만 필수 사항은 아님).
Marco Mp

9
동의하지 않는다. 매우 얇은 공개 API로 복잡한 구성 요소를 구축하는 경우 공개 API를 통해서만 테스트하는 것은 실용적이지 않고 비현실적입니다. 당신은 유지 할 수없는 진흙 공으로 끝날 것입니다. 대신 내부 단위를 신중하게 정의하고 별도로 테스트했습니다. 제레미 디 밀러 (Jeremy D. Miller)는 다음과 같이 자주 말합니다.
Dennis Doomen 2016 년

6

내부 클래스 인 경우 격리 된 상태로 사용해서는 안됩니다. 따라서 내부적으로 해당 객체를 사용하는 다른 클래스를 테스트하는 것과 별도로 테스트해서는 안됩니다.

클래스의 개인 멤버를 테스트하지 않아야하는 것처럼 DLL의 내부 클래스를 테스트해서는 안됩니다. 이러한 클래스는 공개적으로 액세스 가능한 클래스의 구현 세부 사항이므로 다른 단위 테스트를 통해 잘 연습해야합니다.

내부 구현 세부 사항을 테스트하면 테스트가 취약하기 때문에 클래스의 동작 만 테스트하려는 것이 좋습니다. 모든 테스트를 중단하지 않고 모든 클래스의 구현 세부 사항을 변경할 수 있어야합니다.

해당 클래스를 실제로 테스트해야하는 경우, 해당 클래스가 왜 내부에 있는지 이유를 다시 검토 할 수 있습니다.


2
구현 세부 사항은 포괄적 인 테스트의 일부로 실행되어야합니다. 개인 변수를 들여다 보지 마십시오 ... 예상되는 행동을 테스트하십시오. 테스트가 올 바르면 모든 내부 배관 및 배선을 그 일부로 테스트해야합니다. 투표함.
Gishu

69
이 클래스는 DLL 내부의 다른 클래스에 "공개"되어 있으며 클래스의 기능을 독립적으로 테스트해야하므로 반드시 이에 동의하지는 않습니다
leora

27
나도 동의하지 않습니다. 단위는 단위이며 별도로 테스트해야합니다.
Sentinel

5
훌륭한 일반 지침이지만 교의 적으로 다루지 마십시오. 테스트는 두 가지 주요 목적을 제공합니다. 1) 회귀-무언가 깨지지 않았는지 확인합니다. 2) 개발 속도를 높입니다. 코드 줄을 작성하려고 할 때마다 거대한 서비스를 세워야한다면 개발에 방해가 될 것입니다. 복잡한 내부 구성 요소가있는 경우 격리하여 개발하고 테스트 할 수 있기를 원합니다. 반대로, 나는 모든 것을 분리하여 테스트하기를 원하지 않지만 (따라서 회귀 테스트 값을 낮추거나 테스트 코드를 복제 함) 일부 코드는 분리를 정당화합니다. 아마도 열쇠는 별도의 어셈블리로 만드는 것입니다.
이 젠슨

2
여기 OP가 맞습니다. 테스트를 내부 구현에 연결하고 있습니다. 따라서 팀은 테스트와 끔찍한 조롱 코드를 수정하기 위해 영원히 노예입니다. 패키지 된 lib API 또는 네트워크 노출 API 인 경우 공용 API 만 테스트하십시오. 모든 코드는 정문을 통해 행사할 수 있어야합니다. 테스트 구현은 TDD가 크게 사망 한 이유입니다. 시스템의 동작을 보장하는 데 초점을 맞추기보다는 문자 그대로 전체 앱의 모든 클래스를 테스트하는 것은 거대한 PITA입니다. "권한있는"책을 포함하여 거의 모든 사람들이 이것을 잘못했거나 명확하게하지 않았다고 생각합니다.
Luke Puplett

4

문서화 목적으로

또는 Type.GetType메소드 를 사용하여 내부 클래스를 인스턴스화 할 수 있습니다

//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*/ });

제네릭 형식의 경우 다음과 같은 다른 프로세스가 있습니다.

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

수업은 공개 및 봉인이 될 수 있습니다.

그러나 그렇게하지 마십시오.

내부 클래스를 반영하는 툴을 생성하고 리플렉션을 통해 모든 것에 액세스하는 새로운 클래스를 생성 할 수 있습니다. MSTest는 그렇게합니다.

편집 : 원래 어셈블리에 테스트 항목을 포함하지 않으려는 경우; 멤버가 비공개 인 경우에도 작동합니다.


1
무엇을 기다립니다? 당신은 말하지 않는다고 말하는거야 public sealed class? 그 보석에 대한 당신의 추론은 무엇입니까?
호감

@crush traumapony 님은 2009 년부터 로그인하지 않았습니다.
Prof. Falken
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.