답변:
일반적으로 단위 테스트는 클라이언트의 관점에서 결과가 정확하다면 구현이 중요하지 않다는 이론에 따라 클래스의 공용 인터페이스를 다룹니다.
따라서 NUnit은 비공개 멤버를 테스트하기위한 메커니즘을 제공하지 않습니다.
System.Reflection
바인딩 플래그를 사용하여 비공개 메서드에 액세스하고 호출 할 수 있으므로 NUnit을 해킹하거나 자체 프레임 워크를 설정할 수 있습니다. 또는 (쉽게 생각합니다) 컴파일 타임 플래그 (#if TESTING)를 설정하여 액세스 수정자를 변경하여 기존 프레임 워크를 사용할 수 있습니다.
단위 테스트의 초점이 공용 인터페이스 여야한다는 데 동의하지만 개인 메서드도 테스트하면 코드에 대해 훨씬 더 세분화 된 인상을받을 수 있습니다. MS 테스트 프레임 워크에서는 PrivateObject 및 PrivateType을 사용하여이를 허용하지만 NUnit은 그렇지 않습니다. 대신 내가하는 일은 :
private MethodInfo GetMethod(string methodName)
{
if (string.IsNullOrWhiteSpace(methodName))
Assert.Fail("methodName cannot be null or whitespace");
var method = this.objectUnderTest.GetType()
.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
Assert.Fail(string.Format("{0} method not found", methodName));
return method;
}
이 방법은 테스트 가능성을 위해 캡슐화를 손상시킬 필요가 없음을 의미합니다. 비공개 정적 메서드를 테스트하려면 BindingFlags를 수정해야합니다. 위의 예는 인스턴스 메서드에 대한 것입니다.
단위 테스트를 작성하는 일반적인 패턴은 공용 메서드 만 테스트하는 것입니다.
테스트하려는 개인 메서드가 많이있는 경우 일반적으로 코드를 리팩터링해야한다는 신호입니다.
이러한 메서드를 현재 살고있는 클래스에서 공개하는 것은 잘못된 것입니다. 그것은 당신이 그 클래스가 갖기를 원하는 계약을 깨뜨릴 것입니다.
헬퍼 클래스로 이동하여 공개하는 것이 옳을 수 있습니다. 이 클래스는 API에 의해 노출되지 않을 수 있습니다.
이렇게하면 테스트 코드가 공개 코드와 혼합되지 않습니다.
비슷한 문제는 개인 클래스를 테스트하는 것입니다. 어셈블리에서 내 보내지 않는 클래스. 이 경우 InternalsVisibleTo 특성을 사용하여 테스트 코드 어셈블리를 프로덕션 코드 어셈블리의 친구로 명시 적으로 만들 수 있습니다.
테스트중인 대상 어셈블리의 동반자 어셈블리로 테스트 어셈블리를 선언하여 프라이빗 메서드를 테스트 할 수 있습니다. 자세한 내용은 아래 링크를 참조하십시오.
http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx
이것은 대부분 프로덕션 코드에서 테스트 코드를 분리하므로 유용 할 수 있습니다. 이 방법에 대한 필요성을 찾지 못했기 때문에이 방법을 직접 사용한 적이 없습니다. 코드가 어떻게 처리하는지보기 위해 테스트 환경에서 복제 할 수없는 극단적 인 테스트 케이스를 테스트하는 데 사용할 수 있다고 생각합니다.
그래도 말했듯이 개인 메서드를 테스트 할 필요는 없습니다. likley보다 더 작은 빌딩 블록으로 코드를 리팩터링하기를 원합니다. 리팩토링 할 때 도움이 될 수있는 한 가지 팁은 시스템이 관련된 도메인에 대해 생각하고이 도메인에 서식하는 '실제'개체에 대해 생각하는 것입니다. 시스템의 개체 / 클래스는 실제 개체와 직접 관련되어야하며 개체가 포함해야하는 정확한 동작을 격리하고 개체 책임을 제한 할 수 있습니다. 이것은 특정 메소드를 테스트 할 수 있도록하기보다는 논리적으로 리팩토링하고 있음을 의미합니다. 개체 동작을 테스트 할 수 있습니다.
여전히 내부 테스트의 필요성을 느낀다면 코드 한 조각에 집중하고 싶기 때문에 테스트에서 조롱을 고려할 수도 있습니다. 모킹은 객체 종속성을 주입하지만 주입 된 객체는 '실제'또는 프로덕션 객체가 아닙니다. 동작 오류를 쉽게 분리 할 수 있도록 하드 코딩 된 동작이있는 더미 개체입니다. Rhino.Mocks는 기본적으로 개체를 작성하는 인기있는 무료 모의 프레임 워크입니다. TypeMock.NET (커뮤니티 에디션을 사용할 수있는 상용 제품)은 CLR 개체를 모의 할 수있는 더 강력한 프레임 워크입니다. 예를 들어 데이터베이스 앱을 테스트 할 때 SqlConnection / SqlCommand 및 Datatable 클래스를 모의하는 데 매우 유용합니다.
이 답변이 일반적으로 단위 테스트에 대해 알리고 단위 테스트에서 더 나은 결과를 얻는 데 도움이되는 더 많은 정보를 제공하기를 바랍니다.
이 질문은 고급 단계에 있지만이 작업을 수행하는 방식을 공유 할 것이라고 생각했습니다.
기본적으로 모든 단위 테스트 클래스는 해당 어셈블리의 '기본값'아래에있는 'UnitTest'네임 스페이스에 테스트중인 어셈블리에 있습니다. 각 테스트 파일은 다음과 같이 래핑됩니다.
#if DEBUG
...test code...
#endif
블록, 그리고 그것은 모두 a) 릴리스에서 배포되지 않고 b) 후프 점프없이 internal
/ Friend
레벨 선언을 사용할 수 있음을 의미합니다 .
이것이 제공하는 다른 것은이 질문과 더 관련이있는 partial
클래스 의 사용입니다. 클래스를 사용하여 개인 메서드를 테스트하기위한 프록시를 만들 수 있습니다. 예를 들어 정수 값을 반환하는 개인 메서드와 같은 것을 테스트하는 데 사용할 수 있습니다.
public partial class TheClassBeingTested
{
private int TheMethodToBeTested() { return -1; }
}
어셈블리의 기본 클래스 및 테스트 클래스에서 :
#if DEBUG
using NUnit.Framework;
public partial class TheClassBeingTested
{
internal int NUnit_TheMethodToBeTested()
{
return TheMethodToBeTested();
}
}
[TestFixture]
public class ClassTests
{
[Test]
public void TestMethod()
{
var tc = new TheClassBeingTested();
Assert.That(tc.NUnit_TheMethodToBeTested(), Is.EqualTo(-1));
}
}
#endif
개발 중에이 메서드를 사용하지 않도록해야합니다.하지만 릴리스 빌드는 곧 부주의 한 호출을 표시 할 것입니다.
단위 테스트의 주요 목표는 클래스의 공용 메서드를 테스트하는 것입니다. 이러한 공용 메서드는 해당 개인 메서드를 사용합니다. 단위 테스트는 공개적으로 사용 가능한 동작을 테스트합니다.
개인 기능을 테스트하지 않습니다. 리플렉션을 사용하여 개인 메서드 및 속성에 들어가는 방법이 있습니다. 그러나 그것은 정말 쉬운 일이 아니며 저는이 관행을 강력히 권장하지 않습니다.
공개되지 않은 것을 테스트해서는 안됩니다.
내부 메서드와 속성이있는 경우이를 공개로 변경하거나 앱과 함께 테스트를 제공하는 것을 고려해야합니다 (실제로 문제로 보지 않는 것).
고객이 Test-Suite를 실행할 수 있고 제공 한 코드가 실제로 "작동"하는 것을 확인할 수있는 경우 (이를 통해 IP를 제공하지 않는 한) 이것이 문제라고 생각하지 않습니다. 모든 릴리스에 포함 된 것은 테스트 보고서와 코드 커버리지 보고서입니다.
단위 테스트 이론에서는 계약 만 테스트해야합니다. 즉, 클래스의 공개 멤버 만. 그러나 실제로 개발자는 일반적으로 내부 구성원을 테스트하려고합니다. -나쁘지 않습니다. 예, 이론에 위배되지만 실제로는 때때로 유용 할 수 있습니다.
따라서 내부 구성원을 실제로 테스트하려면 다음 접근 방식 중 하나를 사용할 수 있습니다.
코드 예 (의사 코드) :
public class SomeClass
{
protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{
protected void SomeMethod2() {}
[Test]
public void SomeMethodTest() { SomeMethod2(); }
}
Message: Method is not public
. 그렇지 않으면 .
메서드를 내부적으로 보호하고 다음을 사용할 수 있습니다.
assembly: InternalsVisibleTo("NAMESPACE")
테스트 네임 스페이스에 수 있습니다.
따라서 아니오! 개인 메서드에 액세스 할 수는 없지만 이것은 해결 방법입니다.
개인 메서드 패키지를 표시합니다. 이렇게하면 해당 메서드를 테스트 할 수있는 동안 합리적으로 비공개로 유지할 수 있습니다. 나는 사람들이 공개 인터페이스가 테스트되어야 할 유일한 인터페이스라는 말에 동의하지 않습니다. 외부 인터페이스를 통해서만 제대로 테스트 할 수없는 개인 메서드에는 종종 정말 중요한 코드가 있습니다.
따라서 올바른 코드 또는 정보 숨기기에 더 관심이 있는지 여부가 결정됩니다. 나는 패키지 가시성이 좋은 타협이라고 말하고 싶습니다. 그 방법에 액세스하려면 누군가가 자신의 클래스를 패키지에 배치해야하기 때문입니다. 그것은 그들이 정말 똑똑한 일인지에 대해 두 번 생각하게 만들 것입니다.
저는 Java 사람 btw이므로 패키지 visiblilty는 C #에서 완전히 다른 이름으로 불릴 수 있습니다. 이러한 메서드에 액세스하기 위해 두 클래스가 동일한 네임 스페이스에 있어야하는 경우라고해도 충분합니다.