ユニットテストにおける時間の問題についてのTipsです。
ユニットテストを行う際に手間のかかる作業として、テスト用環境の構築があります。
今はDockerがあるのでかなり手間が減りました。
ユニットテストは何度やっても同じテストができて、同じ結果になることが重要ですが、その際に問題となるのはシステム日時です。
「今日」とか「今月」などの日付・時刻によって返す結果が変わる処理があった場合にどうやって環境を設定しておけばよいか。
Docker Composeとlibfaketimeを使ってシステム日時を固定することができます。
以下、PythonのWebフレームワークであるDjangoをサンプルとして方法を紹介します。
他の言語、フレームワークでも基本は同じになります。
1. Dockerfileでlibfaketimeをインストール
FROM python:3
ENV PYTHONUNBUFFERED 1
# テスト時にシステム時刻を固定化するためのlibfaketimeをインストール
WORKDIR /
RUN git clone https://github.com/wolfcw/libfaketime.git
WORKDIR /libfaketime/src
RUN make install
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
2. docker-compose.ymlで環境変数FAKETIMEに固定したい日時を指定
起動すると、コンテナ上の日時が固定された状態になります。
docker-compose.yml
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_PASSWORD: postgres
web:
build: .
command: python3 manage.py runserver 0.0.0.0:8000
environment:
# この2行で日時を設定
- LD_PRELOAD=/usr/local/lib/faketime/libfaketime.so.1
- FAKETIME=2021-04-24 10:30:00
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
3. アプリケーション上での確認
views.py
from django.http import HttpResponse
from datetime import datetime
def index(request):
return HttpResponse(f"Hello, world. "
f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
のようにして、現在日時を表示してみると以下のようにdocker-compose.ymlで設定した日時が表示されます。(何度やっても同じ結果)
備考
後から環境変数FAKETIMEを変更することで、コンテナ的にはシステム日時を変更することができます。
$ date
Sat Apr 24 10:30:00 UTC 2021
$ export FAKETIME="2021-08-22 12:50:33"
$ date
Sun Aug 22 12:50:33 UTC 2021
ただ、Djangoとしては再起動まで反映されません。