문제

미래의 일을 올바르게 계산하기 위해 오늘 날짜를 사용하는 일부 (C#) 코드가 있습니다.오늘 날짜를 테스트에 사용하면 테스트에서 계산을 반복해야 하는데, 느낌이 좋지 않습니다.결과가 알려진 값인지 테스트할 수 있도록 테스트 내에서 날짜를 알려진 값으로 설정하는 가장 좋은 방법은 무엇입니까?

도움이 되었습니까?

해결책

내가 선호하는 것은 시간을 사용하는 클래스가 실제로 다음과 같은 인터페이스에 의존하도록 하는 것입니다.

interface IClock
{
    DateTime Now { get; } 
}

구체적인 구현으로

class SystemClock: IClock
{
     DateTime Now { get { return DateTime.Now; } }
}

그런 다음 원한다면 테스트를 위해 원하는 다른 종류의 시계를 제공할 수 있습니다.

class StaticClock: IClock
{
     DateTime Now { get { return new DateTime(2008, 09, 3, 9, 6, 13); } }
}

시계에 의존하는 클래스에 시계를 제공하는 데 약간의 오버헤드가 있을 수 있지만 이는 다양한 종속성 주입 솔루션(제어 컨테이너 반전, 일반 생성자/세터 주입 또는 심지어는 정적 게이트웨이 패턴).

원하는 시간을 제공하는 개체나 메서드를 전달하는 다른 메커니즘도 작동하지만 중요한 것은 시스템 시계를 재설정하지 않는 것입니다. 그렇게 하면 다른 수준에 문제가 발생할 뿐이기 때문입니다.

또한, DateTime.Now 그리고 이를 계산에 포함시키는 것은 옳지 않다고 느낄 뿐만 아니라 특정 시간을 테스트할 수 있는 능력을 앗아갑니다. 예를 들어 자정 경계 근처나 화요일에만 발생하는 버그를 발견한 경우입니다.현재 시간을 사용하면 해당 시나리오를 테스트할 수 없습니다.아니면 적어도 원할 때는 그렇지 않습니다.

다른 팁

아옌데 라히엔 용도 다소 간단한 정적 방법 ...

public static class SystemTime
{
    public static Func<DateTime> Now = () => DateTime.Now;
}

현재 날짜를 가져오는 것과 같은 간단한 작업을 위해 별도의 시계 클래스를 만드는 것은 다소 과잉이라고 생각합니다.

오늘 날짜를 매개변수로 전달하여 테스트에 다른 날짜를 입력할 수 있습니다.이는 코드를 더욱 유연하게 만드는 추가적인 이점이 있습니다.

Microsoft Fakes를 사용하여 심을 만드는 것은 정말 쉬운 방법입니다.다음과 같은 수업이 있다고 가정해 보겠습니다.

public class MyClass
{
    public string WhatsTheTime()
    {
        return DateTime.Now.ToString();
    }

}

Visual Studio 2012에서는 Fakes/Shim을 만들려는 어셈블리를 마우스 오른쪽 버튼으로 클릭하고 "Fakes 어셈블리 추가"를 선택하여 테스트 프로젝트에 Fakes 어셈블리를 추가할 수 있습니다.

Adding Fakes Assembly

마지막으로 테스트 클래스는 다음과 같습니다.

using System;
using ConsoleApplication11;
using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DateTimeTest
{
[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestWhatsTheTime()
    {

        using(ShimsContext.Create()){

            //Arrange
            System.Fakes.ShimDateTime.NowGet =
            () =>
            { return new DateTime(2010, 1, 1); };

            var myClass = new MyClass();

            //Act
            var timeString = myClass.WhatsTheTime();

            //Assert
            Assert.AreEqual("1/1/2010 12:00:00 AM",timeString);

        }
    }
}
}

성공적인 단위 테스트의 핵심은 디커플링.흥미로운 코드를 외부 종속성과 분리해야 격리된 상태에서 테스트할 수 있습니다.(다행히 테스트 주도 개발은 분리된 코드를 생성합니다.)

이 경우 외부는 현재 DateTime입니다.

여기서 내 조언은 DateTime을 처리하는 논리를 새로운 메서드나 클래스 또는 귀하의 경우에 적합한 모든 항목으로 추출하고 DateTime을 전달하라는 것입니다.이제 단위 테스트에서는 임의의 DateTime을 전달하여 예측 가능한 결과를 생성할 수 있습니다.

Microsoft Moles를 사용하는 또 다른 하나(.NET용 격리 프레임워크).

MDateTime.NowGet = () => new DateTime(2000, 1, 1);

Moles는 .NET 방법을 대의원으로 바꿀 수 있습니다.Moles는 정적 또는 비 빈약 한 방법을 지원합니다.두더지는 PEX의 프로파일 러에 의존합니다.

IDisposable 패턴을 사용하는 것이 좋습니다.

[Test] 
public void CreateName_AddsCurrentTimeAtEnd() 
{
    using (Clock.NowIs(new DateTime(2010, 12, 31, 23, 59, 00)))
    {
        string name = new ReportNameService().CreateName(...);
        Assert.AreEqual("name 2010-12-31 23:59:00", name);
    } 
}

여기에 자세히 설명되어 있습니다.http://www.lesnikowski.com/blog/index.php/testing-datetime-now/

간단한 대답:System.DateTime을 버리세요 :) 대신에 노다타임 테스트 라이브러리입니다. NodaTime.Testing.

추가 자료:

클래스를 주입할 수 있습니다(더 나은:방법/대리자) 당신이 사용하는 DateTime.Now 테스트 중인 수업에서.가지다 DateTime.Now 기본값으로 설정하고 테스트 시 상수 값을 반환하는 더미 메서드로만 설정하세요.

편집하다: Blair Conrad가 말한 것(그는 살펴볼 코드가 있습니다).단, 저는 위임자를 선호하는 경향이 있습니다. 왜냐하면 위임자는 클래스 계층 구조를 다음과 같은 항목으로 복잡하게 만들지 않기 때문입니다. IClock...

나는 이러한 상황에 너무 자주 직면하여 노출되는 간단한 너겟을 만들었습니다. 지금 인터페이스를 통한 속성.

public interface IDateTimeTools
{
    DateTime Now { get; }
}

물론 구현은 매우 간단합니다.

public class DateTimeTools : IDateTimeTools
{
    public DateTime Now => DateTime.Now;
}

따라서 내 프로젝트에 너겟을 추가한 후 단위 테스트에서 사용할 수 있습니다.

enter image description here

GUI Nuget 패키지 관리자에서 바로 모듈을 설치하거나 다음 명령을 사용하여 모듈을 설치할 수 있습니다.

Install-Package -Id DateTimePT -ProjectName Project

Nuget의 코드는 다음과 같습니다. 여기.

Autofac을 사용한 사용 예를 찾을 수 있습니다. 여기.

디버그/배포 중에 발생하는 상황을 제어하기 위해 조건부 컴파일을 사용하는 것을 고려해 보셨나요?

예를 들어

DateTime date;
#if DEBUG
  date = new DateTime(2008, 09, 04);
#else
  date = DateTime.Now;
#endif

실패하면 속성을 노출하여 조작할 수 있어야 합니다. 이는 모두 작성 과제의 일부입니다. 테스트 가능 코드는 제가 현재 고민하고 있는 부분입니다 :D

편집하다

나의 큰 부분은 선호할 것이다 블레어 총리의 접근 방식.이를 통해 테스트에 도움이 되도록 코드의 일부를 "핫 플러그"할 수 있습니다.모든 것은 디자인 원칙을 따릅니다. 변화하는 것을 캡슐화하라 테스트 코드는 프로덕션 코드와 다르지 않으며 외부에서 누구도 볼 수 없습니다.

하지만 이 예제에서는 생성 및 인터페이스가 많은 작업처럼 보일 수 있습니다(이것이 조건부 컴파일을 선택한 이유입니다).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top