나는 이렇게 학습한다/Debug

pytest _ 테스트 코드에서 현재 시간 바꾸는 방법

daco2020 2022. 11. 17. 18:13
반응형

현재 시간을 바꾸는 이유

테스트 코드를 작성하다 보면 현재 시간이 특정 시간을 넘겼을 때 정상적으로 코드가 수행되는지 테스트하고 싶을 때가 있다.

 

예를 들어 만료일자가 있고 오늘 날짜가 만료일자를 지나면 서비스를 중단하는 로직이 있다고 하자. 이를 어떻게 테스트할 수 있을까?

 

오늘 날짜가 아직 만료일자를 지나지 않았기 때문에 이를 테스트하기 위해서는 오늘 날짜 혹은 만료일자를 mock으로 대체하여 구현해야 한다. 하지만 mock을 직접 구현하는 데에는 코스트가 들기 때문에 아무래도 꺼려지는 방법이다.

 

만약 당신이 pytest를 사용한다면 pytest-freezegun 라이브러리를 이용해 이 문제를 쉽게 해결할 수 있다.

 

 

 

 

pytest에서 시간 freeze 하는 방법

먼저 pytest-freezegun 라이브러리를 설치한다.

pip install pytest-freezegun

 

 

 

1. 현재시간 얼리기

테스트에 사용할 모듈을 Import 하자.

from datetime import datetime
import time

 

 

pytest-freezegun 는 별도로 import 하지 않고 테스트 함수의 fixture 로 사용할 수 있다.

def test_현재시간_얼리기(freezer): # <- 매개변수로 freezer fixture를 가져온다. 
    ...

 

 

(코드 확인)

def test_현재시간_얼리기(freezer):
    # given
    현재시간1 = datetime.now()

    # when
    time.sleep(1)
    현재시간2 = datetime.now()

    # then
    assert 현재시간1 == 현재시간2

현재시간1을 구하고, 1초 대기한 후 다시 현재시간2을 구한다.

현재시간2는 현재시간1보다 1초 뒤에 생성했지만 이 둘의 시간은 같다!

 

 

 

 

2. 현재시간 바꾸기

freezer 인자의 move_to() 를 이용하면 시간을 내 마음대로 지정할 수 있다.

# 날짜만 지정할 경우
freezer.move_to("2022-12-25") 

# 시간까지 지정할 경우
freezer.move_to("2022-12-25 12:30:00")

 

 

(코드 확인)

def test_현재시간_바꾸기(freezer):
    # given
    현재시간1 = datetime.now()

    # when
    freezer.move_to("2022-12-25")
    현재시간2 = datetime.now()

    # then
    assert 현재시간1.date() == datetime(2022, 11, 17).date()
    assert 현재시간2.date() == datetime(2022, 12, 25).date()

현재시간1 는 오늘 날짜이다.

현재시간2 는 지정한 대로 2022년 12월 25일이다.

 

같은 now() 함수를 이용했지만 move_to() 이용해 다른 날짜를 지정할 수 있다.

 

 

 

 

3. 현재시간 고정하기

freeze_time() 데코레이터를 이용하면 함수 밖에서 시간을 지정할 수 있다!

# 날짜만 지정할 경우
@pytest.mark.freeze_time("2050-01-01")
def test_현재시간_고정하기(freezer):
    ...

# 시간까지 지정할 경우
@pytest.mark.freeze_time("2050-01-01 12:30:00")
def test_현재시간_고정하기(freezer):
    ...

 

 

먼저 데코레이터를 사용하기 위해 pytest 를 import 한다.

import pytest

 

 

(코드 확인)

@pytest.mark.freeze_time("2050-01-01")
def test_현재시간_고정하기(freezer):
    # when
    현재시간 = datetime.now()

    # then
    assert 현재시간.date() == datetime(2050, 1, 1).date()

현재시간 이 데코레이터에서 지정한 대로 2050년 1월 1일 임을 알 수 있다.

 

 

 

 

4. 만료시간 테스트하기(실전연습)

현재시간이 만료시간을 넘기면 “NO” 를 반환하는지 테스트해보자.

@pytest.mark.freeze_time("2022-12-01 09:30:01")
def test_만료시간를_넘기면_NO를_반환(freezer):
    # given
    현재시간 = datetime.now()
    만료시간 = datetime(2022, 12, 1, 9, 30, 0)

    # when
    if 현재시간 <= 만료시간:
        결과 = "GO"
    else:
        결과 = "NO"

    # then
    assert 결과 == "NO"

만료시간은 2022년 12월 1일 9시 30분 이고,

현재시간이 2022년 12월 1일 9시 30분 1초 으로 가정했다.

 

if와 논리 연산자를 통해 결과가 “NO” 로 반환되는 것을 테스트 및 확인하였다!

 

 

 

 

정리

  • 현재시간을 이용해 테스트를 해야 하는 경우가 있다.
  • 하지만 현재시간은 계속해서 변하므로 테스트하기가 어렵다.
  • pytest-freezegun 을 이용하면 현재시간을 고정하거나 변경할 수 있다.

 

 

 

공식문서

 

GitHub - ktosiek/pytest-freezegun: Easily freeze time in pytest test + fixtures

Easily freeze time in pytest test + fixtures. Contribute to ktosiek/pytest-freezegun development by creating an account on GitHub.

github.com

 

 

반응형