2009-08-13 6 views
4

우리 팀은 단위 테스팅과 조롱을 막 시작했으며, 확장 방법을 고려해 토론을 진행했습니다. 문제는 확장 메서드를 사용하여 클래스를 테스트하는 좋은 방법입니다. 나는. 우리는이 같은 열거가 .. 확장 방법을 사용합니다단위 테스팅 확장 방법

public enum State 
{ 
    [LangID(2817)] 
    Draft = 0, 
    [LangID(2832)] 
    Booked = 1, 
    [LangID(1957)] 
    Overdue = 2, 
    [LangID(2834)] 
    Checked = 3, 
} 

: 다시과 같이, 테스트중인 클래스에 의해 호출됩니다

public static string GetDescription(this Enum _enum) 
{ 
    Type type = _enum.GetType(); 
    MemberInfo[] memInfo = type.GetMember(_enum.ToString()); 
    if (memInfo != null && memInfo.Length > 0) 
    { 
     object[] attrs = memInfo[0].GetCustomAttributes(typeof(LangID), false); 
     if (attrs != null && attrs.Length > 0) 
      return LanguageDB.GetString(((LangID)attrs[0]).ID); 
    } 
    return _enum.ToString(); 
} 

..

public class SUT(){ 

    public void MethodUnderTest(){ 
     string description = SomeObject.Status.GetDescription();//Status is Type State 
    } 
} 

이 예제에서 열거 형은 LanguageDB를 통해 사용자의 언어로 설명을 얻고 있습니다. LanguageDB는 정적이므로 클래스 내부에 삽입되지 않습니다. 우리는 자연스럽게 굴절시킬 수 있지만 코드가 거의 완벽하게 작동한다는 점을 감안할 때 큰 투자가 될 것입니다. 좋은 제안이 있으십니까?

+1

질문은 언어 DB를 조롱하는 방법입니다 (수행해야하는 경우). –

+0

그럼 다음과 같이 구현할 수도 있습니다 : If (InTesTMode) return; // 그러나 나는 정말로 그 좋은 생각을 생각하지 않는다 ;-) – BBorg

답변

7

MS '테스트 스위트를 사용하는 경우 매우 간단한 리팩토링을 수행하고 접근자를 사용하여 정적 유형 객체에 모의 객체를 삽입 할 수 있습니다.

는의가이 같은 코드를 가지고 있다고 가정 해 봅시다 : 하드

정적 내
public static void Save(this Entity data) 
{ 
    Repository.Instance.Save(data); 
} 

정적이 ... 테스트? 그렇지 않아. 따라서 확장 클래스를 수정하십시오.

private static Repository Instance 
{ 
    get 
    { 
    return _repository ?? Repository.Instance; 
    } 
} 
private static Repository _repository = null; 

public static void Save(this Entity data) 
{ 
    Instance.Save(data); 
} 

간단한 리펙터. 지금, 당신은 ... 시험 시간에 모의를 설정하는 접근을 사용할 수 있습니다

[TestInitialize(), DebuggerStepThrough] 
public void Setup() 
{ 
    MyEntityExtensions_Accessor._repository = new Mock<IRepository>(); 
} 
+0

좋은 대답, 우리는 typemocks를 고려한다. 그러나이 솔루션은 실제로 우리 문제의 95 %를 해결할 것입니다. 주요 refractoring없이, thx – BBorg

+0

만약 누군가가 널 체크에서 당신은 그것을 한 번만 더 그것을 단순화 할 수 있습니다 : ** return _repository ?? (_repository = Repository.Instance); ** – Will

+0

한 가지 더 ... 위의 작업을 수행하면 (한번 null 체크) 한 번 설정 한 다음 모의 객체를 재사용해야합니다 (이 작업 만 수행 할 수 있습니다). appdomain 당 한 번). 매번 새로운 모의 인스턴스를 설정할 수 있도록 Repository를 확장하는 유형의 모의를 작성해야 할 수도 있습니다. – Will

5

거의? ;-)

규칙 1 : 테스트 할 수없는 경우 쓰지 마십시오.

규칙 2 : 많은 것들은 tehy가 상처를 입는 것처럼 보이지만 그렇지 않습니다.

이 리팩토링이 큰 투자가 될 것이라고 확신하십니까?

규칙 0 : 규칙은 현자의지도를위한 것이고 바보의 순종을위한 것입니다.

이것은 작품을 통해 그 방법의 결함을 얼마나 피할 수 있는지 판단하는 것입니다. 내 생각에이 경우 리팩토링의 이점은 매우 작습니다.

1

자체가 가 얻을 수행하는 모든 작업을 수행 private 메소드를 가질 수 확장 방법을 것입니다 테스트를위한 하나 개의 아이디어 LanguageDB가 주입되었습니다. 공용 메서드는 정적 LanguageDB를 사용하여 private 메서드를 호출하지만 실제로 리플렉션을 통해 전용 메서드를 테스트하고 mock 개체를 전달합니다.

테스트중인 실제 클래스를 테스트하는 경우 정적 LanguageDB를 대체 할 방법이 필요합니다. 실제로 null을 빼고 실제로 열거 형 이름을 얻고 있는지 테스트해야합니다. 결국 확장 기능이 다른 곳에서 작동하는지 이미 테스트 했으므로이 클래스에서 다시 테스트 할 필요가 없습니다.

궁극적으로 정적 개체를 테스트하기가 어렵다는 것을 알게됩니다.당신이 이미 짐작했던 것처럼 진짜 대답은 피할 수 있으면 정적 인 객체에 의존하지 않는 더 나은 디자인으로 리팩터링하는 것입니다 (이것이 좋은 후보 인 것처럼 보이지만). 아마도 리팩터링을 통해 주입을 포함 할 수 있습니다.

+0

예, refractoring은 WTG 인 것 같습니다. – BBorg