Flask のテストの ResourceWarning への対処

Flask を使ってバイナリを返すようなコードを書いていました。

from os.path import dirname
from flask import Flask, send_from_directory

app = Flask(__name__)

@app.route('/')
def hello_world():
    return send_from_directory(directory=dirname(app.instance_path),
                               filename='python.png')

内容は上記のような感じで、

set -lx FLASK_APP hello.py
flask run

で実行し、ブラウザで localhost:5000 にアクセスすると画像が表示されます。これに対してテストを書くと、以下のような感じになるかと思います。

from http import HTTPStatus
from unittest import TestCase

from hello import app

class TestHello(TestCase):
    def setUp(self):
        super().setUp()
        self.client = app.test_client()

    def test_hello(self):
        dat = None
        with open('python.png', 'rb') as fp:
            dat = fp.read()

        resp = self.client.get('/')
        self.assertEqual(resp.status_code, HTTPStatus.OK)
        self.assertEqual(resp.data, dat)

これでユニットテストを実行すると、一応成功するものの以下のような警告が出力されます。

/usr/local/Cellar/python/3.7.2/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py:615: ResourceWarning: unclosed file <_io.BufferedReader name='/Users/mits/work/aaa/python.png'>
 testMethod()
ResourceWarning: Enable tracemalloc to get the object allocation traceback
.
----------------------------------------------------------------------
Ran 1 test in 0.021s
OK

タイトルでは Flask のというように書きましたが、実際には unittest でファイル的な何かを開くけどきちんと閉じない場合に起こる警告のようです。 assertion の後で明示的に resp を閉じたり、 with ブロックを使うようにしたらこの警告は出ないようになるようです。インデントが深くなるのが少し気になりますが、僕は with を使って以下のように書きました。

    def test_hello(self):
        dat = None
        with open('python.png', 'rb') as fp:
            dat = fp.read()

        with self.client.get('/') as resp:
            self.assertEqual(resp.status_code, HTTPStatus.OK)
            self.assertEqual(resp.data, dat)


この記事が気に入ったらサポートをしてみませんか?