LoginSignup
0
0

More than 1 year has passed since last update.

# pytest 一時ディレクトリを使いダミーファイルでテスト

Posted at

キーワード: tmp_path, monkeypatch.chdir

できること

テスト時は実際にファイルを参照せずに、ダミーファイルから参照させるようにする。

下記ディレクトリ構成で、 input/sample.csv が通常実行時に参照されるファイル。テスト時には、参照しないようにする。

❯ tree -L 2 .
.
├── input
│   └── sample.csv
├── requirements.txt
├── src
│   └── app.py
└── tests
    ├── __init__.py
    └── test_app.py

コード

import csv
import os

def main():
    print(os.getcwd())
    with open('input/sample.csv', 'r') as file:
        reader = csv.reader(file)
        for row in reader:
            print(row)

if __name__ == '__main__':
    main()
import pytest
import csv
import os

@pytest.fixture
def set_test_csv(tmp_path):
    rows = [['Name', 'Age', 'City'],
            ['John', '30', 'New York'],
            ['Jane', '25', 'London']]
    os.mkdir(tmp_path / 'input')
    csv_file_name = tmp_path / 'input/sample.csv'
    with open(csv_file_name, 'w', newline='') as file:
        writer = csv.writer(file)
        writer.writerows(rows)

@pytest.fixture
def main(tmp_path, monkeypatch):
    monkeypatch.chdir(tmp_path)
    from src.app import main
    return main

def test_app(tmp_path, set_test_csv, main):
    main()
    assert True

解説

app.pyの main では、ハードコーディングで input/sample.csv が指定されている。(こんなクソコードがないという話は置いておく)

test_app.pyの set_test_csv でダミーのテストファイルを作成している。 tmp_path (pytestの組込みfixture)という一時ディレクトリ配下に同じディレクトリを掘りファイル作成。

def main の実装がポイント。

  • fixtureとして定義
  • tmp_path , monkeypath.chdir でカレントディレクトリを tmp_path に変更
  • カレントディレクトリ変更後に、テスト対象のモジュールから関数をimport

main自体をfixtureにしているのは、 monkeypatch.chdir(tmp_path) のロジックをimport前に差し込みたいため。
これより前にimport すると実際のファイルを参照してしまう。

test_app のフローは、下記のような感じ。

  1. set_test_csv でダミーファイルを作成(fixtureの引数)
  2. main でカレントディレクトリを一時ディレクトリに置き換えて、テスト対象関数のimport
  3. main() で関数を実行。→このとき、ダミーファイルが参照される
  4. 要件に沿って assert

最後に

tmp_path_factory がよくわかってないので、場合によっては使うべきかも。

The tmp_path_factory is a session-scoped fixture which can be used to create arbitrary temporary directories from any other fixture or test.

notion AI改善バージョン

以下、notion AIに改善してもらったバージョン。

です・ます調になっただけかな??

できること

テスト時には、実際のファイルを参照せずに、ダミーファイルから参照させることができます。

下記ディレクトリ構成で、input/sample.csv は通常実行時に参照されるファイルです。テスト時には、参照しないようにする必要があります。

❯ tree -L 2 .
.
├── input
│   └── sample.csv
├── requirements.txt
├── src
│   └── app.py
└── tests
    ├── __init__.py
    └── test_app.py

コード

import csv
import os

def main():
    print(os.getcwd())
    with open('input/sample.csv', 'r') as file:
        reader = csv.reader(file)
        for row in reader:
            print(row)

if __name__ == '__main__':
    main()

import pytest
import csv
import os

@pytest.fixture
def set_test_csv(tmp_path):
    rows = [['Name', 'Age', 'City'],
            ['John', '30', 'New York'],
            ['Jane', '25', 'London']]
    os.mkdir(tmp_path / 'input')
    csv_file_name = tmp_path / 'input/sample.csv'
    with open(csv_file_name, 'w', newline='') as file:
        writer = csv.writer(file)
        writer.writerows(rows)

@pytest.fixture
def main(tmp_path, monkeypatch):
    monkeypatch.chdir(tmp_path)
    from src.app import main
    return main

def test_app(tmp_path, set_test_csv, main):
    main()
    assert True

解説

app.pymain では、ハードコーディングで input/sample.csv が指定されています。(こんなクソコードがないという話は置いておきます)

test_app.pyset_test_csv でダミーのテストファイルを作成しています。 tmp_path (pytestの組込みfixture)という一時ディレクトリ配下に同じディレクトリを掘り、ファイルを作成します。

def main の実装がポイントです。

  • fixtureとして定義
  • tmp_pathmonkeypatch.chdir でカレントディレクトリを tmp_path に変更
  • カレントディレクトリ変更後に、テスト対象のモジュールから関数をimport

main 自体をfixtureにしているのは、 monkeypatch.chdir(tmp_path) のロジックをimport前に差し込みたいためです。

これより前にimport すると実際のファイルを参照してしまいます。

test_app のフローは、下記のような感じです。

  1. set_test_csv でダミーファイルを作成(fixtureの引数)
  2. main でカレントディレクトリを一時ディレクトリに置き換えて、テスト対象関数のimport
  3. main() で関数を実行。→このとき、ダミーファイルが参照されます
  4. 要件に沿って assert

最後に

tmp_path_factory がよくわかっていないので、場合によっては使うべきかもしれません。

The tmp_path_factory is a session-scoped fixture which can be used to create arbitrary temporary directories from any other fixture or test.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0