2011-01-20 2 views
4

나는 테스트 할 동작이있는 보호 된 메서드로 봉인 된 클래스가 있습니다. 이렇게하면 직접 테스트하기가 어렵고 모의하기가 어렵습니다.C# : 봉인 된 클래스에서 모의 ​​및 보호 된 (또는 개인) 메서드 - 접근 방식

TDD 방식으로 개발되지 않은 코드베이스에 있으며, 이제 특정 기능에 대한 단위 테스트를 추가하고 있습니다.

이 경우 가능한 일반적인 접근 방법은 무엇입니까? 현재 내가 가지고있는 것 :

  1. 수업을 개봉하지 않았습니까? 그런 다음 테스트 코드에서 클래스에서 파생 된 프록시 또는 어댑터를 만들어 보호 된 메서드에 대한 액세스를 터널링합니다.
  2. 보호 된 메서드의 비헤이비어를 대리자/함수 작성자로 가져 와서 다시 삽입합니다. 그런 다음 독립적으로 분해 된 동작을 테스트하십시오.
  3. 보호 된 메서드를 사용하는 상속 계층 구조에서 가장 가까운 public 메서드를 호출하여 테스트합니다. 시험 대상이 아닌 다른 코드가 변경되면 위험에 노출되어 조잡한 테스트 결과를 초래할 수 있습니다.
  4. 보호 된 방법에 액세스하려면 리플렉션을 사용하십시오. 그런 다음 직접 호출하십시오.

더 이상 있습니까?

답변

7

봉인 클래스에서 protected 방법은 효과적으로 private (당신이 기본 클래스가이 자연스럽게 올 수있는 protected 멤버가 파생 클래스를 밀봉하는 경우 같아요.)

과 동일하며 아무 소용 테스트가 없습니다 private 방법. 정의 클래스의 public 메서드를 통해 액세스 할 수있는 것을 제외하고는 public 동작이 없기 때문에 public 메서드를 테스트하여 해당 동작을 테스트해야합니다.

+0

몇 번이나 공용 메서드를 테스트하려면 개인 메서드를 조롱하는 것이 편리합니다. 내 생각에 그것은 주요 사용 사례입니다. – anthares

+0

@anthares : 그건 잘못된 것 같습니다. 'private' 메쏘드가'public' 메쏘드 구현의 일부분이라면 그것은 조롱 거리가되어서는 안됩니다. – jason

+0

글쎄요, 예를 들면 : 리플렉션을 사용하여 특정 보호 된 메소드를 직접 호출하기 위해 필요한 모든 것을 조롱하는 데 좋은 반나절이 걸렸습니다. 가장 가까운 공개 방법에서 모든 것을 조롱해야한다면 완성을 위해 자녀에게 과제를 전달해야 할 수도 있습니다. 그것은 내가 일반적으로 당신에게 동의하지 않는다고 말하는 것은 아닙니다. 단지 코드베이스가 다른 실질적인 제약이 있다는 것입니다. (+1) –

1

조롱을위한 몇 가지 프레임 워크를 사용할 수 있습니다. 예를 들어 JustMock (Telerik 제공)은 봉인 된 개인 방법 모의를 지원합니다 ... 불행히도 JustMock의이 부분은 지불되었지만 적어도 시험 버전을 사용해 볼 수는 있습니다.

+0

Handy, ta; 나는 Rhino Mocks를 사용하고 있습니다. –

2

일반적으로 두 번째 옵션을 선택하면 변경 사항을 상당히 쉽게 적용 할 수 있다고 가정합니다. 감안할 때 공용 인터페이스를 통해 보호 된/개인 메서드를 수행 할 수 없다면 어쨌든 단일 책임 원칙을 따르지 않을 것이며 코드는 아마도 두 클래스로 나누어 져 대신 구성을 사용할 수 있습니다.

3

Microsoft Moles 비 - 가상 메서드로 개봉되지 않은 클래스를 조롱하는 데 도움이됩니다. 개인적인 방법을 조롱 할 수는 없지만, 이것은 특정 클래스 외부에서 사용되는 더 높은 수준의 공용 메서드를 모방 할 수 있고 하나의 공용 메서드를 조롱하는 모든 필요한 동작을 에뮬레이션 할 수 있기 때문에 중복됩니다.

왜 개인/보호 된 방법을 테스트해야합니까? 이를 달성하기 위해 내부 메소드와 InternalVisibleToAttribute을 사용할 수 있습니다. 하지만 일반적으로 공개 행동 (예 : 공개 인터페이스) 만 테스트해야합니다.

+0

Moles 포인터에 감사드립니다. 매우 흥미 롭습니다. 제이슨에게 대중적인 방법을 조롱하는 것에 대한 빠른 대답을했습니다. –

1

JustMock 프레임 워크를 사용할 수 있습니다. 예 :

double value = 0; 
var fakeFilterSetHelper = Mock.Create<FilterSetHelper>(Behavior.CallOriginal); 
Mock.NonPublic.Arrange<double>(fakeFilterSetHelper, memberName: "GetPriceRangeFromSession").Returns(value); 
관련 문제