2013-07-03 2 views
2

시간 의존적 인 방법을 어떻게 테스트하겠습니까?UnitTest 시간 의존적 인 방법

간단한 예는 수 :

public static int GetAge(DateTime birthdate) 
{ 
    // ... 
} 

[TestMethod] 
public void GetAgeTest() 
{ 
    // This is only ok for year 2013 ! 
    Assert.AreEqual(GetAge(new DateTime(2000, 1, 1)), 13); 
} 

문제는 (이 경우 2013) 현재 연도에 대해서만 작동한다는 것입니다. 새해가 시작 되 자마자 모든 시간 의존적 인 테스트를 다시 작성해야합니다 ...

단위 테스트에 가장 적합한 방법은 무엇입니까?

답변

2

두 가지 주요 옵션 :

  1. 이 시간에 따라 기능을 분리하는 서비스를 만들고 필요한 클래스로의 인터페이스를 주입. 그런 다음이 인터페이스를 조롱하여 테스트에 필요한 동작을 얻을 수 있습니다.

  2. DateTime.Now과 같은 정적 메서드 호출을 리 라우팅 할 수있는 Moles과 같은 우회 테스트 프레임 워크를 사용하십시오.

+0

Moles가 재미있는 것 같습니다. 여기에 예제가 있습니다. http://stackoverflow.com/questions/5961982/using-moles-with-datetime 불행히도 Moq와 같은 모의 프레임 워크는 라우팅이나 정적 메소드를 지원하지 않습니다./property like'DateTime.Now' – Bidou

4

GetAge 메서드가 오늘 날짜를 찾는 메커니즘을 무시할 수 있습니다.

DateTime 다른 클래스로 래핑하면 단위 테스트 중에 알려진 값을 반환하는 가짜 호출로 실제 호출을 바꿀 수 있습니다.

종속성 삽입을 사용하면 실제 실제 구현과 테스트 용 가짜 구현간에 전환 할 수 있습니다. 이 같은

+0

나는 그것을 시도했다; 그러나 이것은 너무 많은 오버 헤드를 추가하는 것으로 보입니다. 또한 종속성을 주입하기 위해 정적 헬퍼에 약간 성가신 정적 메서드를 사용할 수 없습니다. – Bidou

+0

@Bidou. 그렇습니다. 상대적으로 간단한 테스트의 오버 헤드입니다. 그러나 더 복잡한 테스트의 경우 자체 테스트로 들어갑니다. – ChrisF

+3

@ 비두, 어색함을 더합니다. 그것은 흥미로운 질문을 제기합니다. 그렇기 때문에 처음에 타이밍 정보에 의존하는 테스트 대상이되는 이유는 무엇입니까? GetAge 메서드는 실제로 DateTime.Now에 절대적으로 의존해야합니까? 아니면 참조 DateTime을 매개 변수로 받아들이는 것이 더 합리적입니까? 여기서 테스트 가능성의 어려움은 약간 다른 디자인으로 제거 될 수있는 불필요한 의존성을 나타냅니다. –

1

뭔가는 "예상"인수가 AreEquals 최초의 하나입니다 잊지 마세요, 트릭 또한

var birthDate = new DateTime(DateTime.Now.Year - 13, 1, 1) 
int age = GetAge(birthDate); 
Assert.AreEqual(age, 13); 
+1

이 테스트는 새해 이브에서 실행될 때 해당 연도가 올바르게 변경되었을 때 실패 할 수 있습니다. –

+0

@Dan Bryant : 정말 극단적 인 사례입니다 ... 100.000.000 ... 1, 1000.000.000.000 ... 1 ... 개인적으로는 거의 불가능하기 때문에 걱정하지 않으려 고합니다. 의견 –

+1

@ Dan : 잘 발견! 중요한 시간에 단위 테스트를 실행하는 대신 샴페인 한 잔을 마셔서 문제를 피할 수 있습니다 ;-) – Treb

3

할 것입니다.

[TestMethod] 
public void GetAgeTest() 
{ 
    int age = 13; 
    Assert.AreEqual(age, GetAge(DateTime.Now.AddYears(age * -1)); 
} 

또한 정렬에서 시험을 분할 좋을 것이다 - 법 - 같은 그룹을 어설 :

[TestMethod] 
public void GetAgeTest() 
{ 
    // Arrange 
    int age = 13; 

    // Act 
    int result = GetAge(DateTime.Now.AddYears(age * -1); 

    // Assert 
    Assert.AreEqual(age, result); 
} 
+0

이것에 관해서는 Claudio의 대답과 마찬가지입니다. 희소 경쟁 상태로 인해이 테스트가 실패 할 수 있습니다. 이것은 현재 시간에 직접 의존하는 테스트 방법의 근본적인 문제입니다. –

+0

@DanBryant 섣달 그믐 날에 미친 행운으로 자동화 된 테스트 슈트가 한 번 실패하더라도, 아무도 그것을 볼 수있는 직장에있을 것이라고는 생각하지 않습니다. 하하 –

1

또 다른 솔루션은 마이크로 소프트 Shimes와 페이크를 사용하는 것입니다. 어쩌면 http://msdn.microsoft.com/en-us/library/hh549175.aspx

using (ShimsContext.Create()) 
{ 
    // Shim DateTime.Now to return a fixed date: 
    System.Fakes.ShimDateTime.NowGet =() => 
    { 
     return new DateTime(fixedYear, 1, 1); 
    }; 
} 
0

하지 최선이 특정한 경우에 옵션,하지만 당신은 또한 당신의 함수의 인터페이스도 DateTime now을 요구하는 확장 할 수에서 봐이 전달 될 수 있습니다.

public static int GetAge(DateTime birthdate, DateTime now) 
{ 
    // ... 
} 

[TestMethod] 
public void GetAgeTest() 
{ 
    Assert.AreEqual(GetAge(new DateTime(2000, 1, 1), new DateTime(2013, 1, 1)), 13); 
} 

당신은 기본적으로 호출자에게 현재 날짜를 가져 오는 책임을 위임합니다 (단, 여기에도 단위 테스트 문제가 있습니다).

좋은 부작용은이 함수의 경계 내에서 실제로 "잘 정의 된"것을 얻는 것입니다. 틱 수준에서 DateTime.Now를 호출하면 변화가 생깁니다. 이 기능을 추상적 수준에서 "이 생년월일 및 현재 날짜, 연령"이라고 설명 할 수 있습니다.

다시 말하지만,이 방법이 모든 상황에서 가장 좋은 방법은 아니지만 일부 고려할 가치가 있다고 생각합니다.

관련 문제