Тестирование нескольких запускаемых клиентских приложений - Python, Flask - PullRequest
1 голос
/ 30 октября 2019

Вопрос Как протестировать блокирующее приложение cli в Python?

Что я пытаюсь выполнить

У меня есть файл manage.py, который используется для запуска веб-сервера разработки фляги (и других действий администратора, которые отсутствуюто объеме этого вопроса). Обычно я запускаю это как python manage.py runserver, но для простоты и актуальности этого вопроса я отредактировал этот файл (см. «Минимальный, воспроизводимый пример»), чтобы просто запустить сервер. Таким образом, приведенная ниже команда работает

$ python manage.py 
 * Serving Flask app "app" (lazy loading)
 * Environment: production...

Проблема заключается в тестировании функциональности этого приложения Cli. Click имеет CliRunner.invoke () , который позволяет тестировать cli приложения. Но в данном конкретном случае происходит сбой, так как сервер уже работает.

from manage import runserver
from click.testing import CliRunner
import requests
import unittest


class TestManage(unittest.TestCase):

    def test_runserver(self):
        runner = CliRunner()
        runner.invoke(runserver)
        # It blocks above, does not go below!
        r = requests.get('http://127.0.0.1')
        assert r.status_code == 200


if __name__ == '__main__':
    unittest.main()

Попытки решения

После попытки многих подходов я нашел «решение», который должен вызвать Process , чтобы запустить сервер, запустить тесты и затем завершить процесс при выходе (это включено в пример). Это больше похоже на взлом, а не на «реальное» решение.

Минимальный, воспроизводимый пример

  • Структура папки

    flask_app/
       - app.py
       - manage.py
       - test_manage.py
    
  • app.py

    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello():
        return 'Hello, World!'
    
  • manage.py

    import click
    from app import app
    
    
    @click.command()
    def runserver():
        app.run()
    
    
    if __name__ == "__main__":
        runserver()
    
  • test_manage.py

    from manage import runserver
    from multiprocessing import Process
    from click.testing import CliRunner
    import requests
    import unittest
    
    
    class TestManage(unittest.TestCase):
    
        def setUp(self):
            self.runner = CliRunner()
            self.server = Process(
                target=self.runner.invoke,
                args=(runserver, )
            )
            self.server.start()
    
        def test_runserver(self):
            r = requests.get('http://127.0.0.1')
            assert r.status_code == 200
    
        def tearDown(self):
            self.server.terminate()
    
    
    if __name__ == '__main__':
        unittest.main()
    

И запустите тест, используя $ python test_manage.py.

1 Ответ

0 голосов
/ 03 ноября 2019

Если вы просто пытаетесь протестировать приложение cli, я бы предложил просто протестировать приложение cli. Для этого вам следует макет фактический запуск сервера, например:

from manage import runserver
from click.testing import CliRunner
import unittest
from unittest import mock


class TestManage(unittest.TestCase):

    def test_runserver(self):
        runner = CliRunner()
        with mock.patch('manage.app.run') as app_run:
            runner.invoke(runserver)
        app_run.assert_called_with()


if __name__ == '__main__':
    unittest.main()

Этот макет метод app.run(), а затем гарантирует, что он былвызвали, и что это было вызвано с ожидаемыми аргументами.

...