Как выполнить подпроцессинг tcp-сервера pymodbus в модульном тесте python и завершить его после выполнения всех тестов?

Я постараюсь дать вам некоторый контекст, прежде чем рассказывать о проблеме, с которой я столкнулся. У меня есть компонент под названием Actuator, который полагается на модуль pymodbus. Когда я тестировал этот компонент, я делал это самым простым способом, используя TCP-сервер Modbus, основанный на pymodbus. По сути, я запускаю сервер как скрипт python (который является именно таким: https://pymodbus.readthedocs.io/en/latest/source/example/synchronous_server.html) в новой оболочке и мое приложение, которое включает Actuator, в другой оболочке. Все работает как шарм.

Сейчас я хочу написать модульный тест для Actuator, используя python unittest и pymodbus, и попытаться автоматизировать то, что я делал раньше. Моя идея заключалась в том, чтобы запустить сервер Modbus в качестве подпроцесса (учтите, что мне не нужен вывод с сервера) в методе setUp, использовать его в моем наборе тестов, а затем завершить его в методе tearDown, например:

class TestActuator(unittest.TestCase):
    """Class to test the actuator module"""

    def setUp(self):
        """
        Setup a real Actuator object with a modbus server running
        in background for tests
        """
        modbus_server_path = "path/to/modbus_server.py"
        cmd = "python3 {}".format(modbus_server_path)
        self.modbus_server = Popen(cmd.split(), shell=False, stdout=DEVNULL, stderr=DEVNULL)

        # other stuff

    def test1(self):
 
    def test2(self):

    def tearDown(self):
        """Cleanup everything before exiting"""

        self.modbus_server.terminate()


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

К сожалению, это оказалось сложнее, чем я ожидал. Все, что я пробовал из других тем в stackoverflow, не удалось:

  • Используйте Popen.kill () вместо terminate. Я также пытался выполнить del после kill или terminate или вместо этого использовать os.kill (self.modbus_server.pid, SIGTERM).
  • Добавьте или измените аргументы в команде Popen, например shell = True вместо shell = False и close_fds = True.
  • Используйте другие варианты подпроцесса Popen, такие как check_output, run, call и т. Д.
  • Используйте os.spawnl вместо подпроцесса Popen.

Ничего из этого не сработало. В большинстве случаев сервер не запускается должным образом, поэтому все остальные тесты терпят неудачу и процесс modbus_server не завершается (мне приходится его убить вручную).

Есть ли у вас какие-либо идеи? Спасибо.


person Rick    schedule 28.09.2020    source источник


Ответы (1)


Я расскажу, как я решил свою проблему и что я узнал на данный момент:

Что касается попытки заставить сервер Modbus TCP работать как подпроцесс во время выполнения тестов, вам нужно изменить несколько вещей, чтобы он работал нормально.

Во-первых, используйте setUpClass и tearDownClass вместо setUp и tearDown (вы также можете использовать их оба, но в моем случае мне понадобились первые два), чтобы вы могли запустить настройку своего сервера только один раз для всего набора тестов. а не до и после каждого теста. К сожалению, синтаксис setUpClass и tearDownClass не так прост. Этот ответ мне очень помог: Запустите setUp только один раз для набор автоматических тестов

Второе - о TCP-сокете. По сути, я хотел убедиться, что мои тесты работают нормально, и запустить их несколько раз подряд. Итак, иногда все работало нормально, иногда - нет. Через некоторое время я обнаружил, что, если я запускаю тесты, не дожидаясь хотя бы одной минуты перед повторной попыткой, они потерпят неудачу. Это связано с TIME_WAIT (по умолчанию установлено 60 секунд) сокета TCP, привязанного сервером Modbus к локальному адресу и порту 5020 в моем случае. Если вы хотите повторно привязать сокет к тому же TCP-адресу и порту, которые вы использовали раньше, вам придется подождать 60 секунд. Этот ответ был полезен, чтобы понять, почему это происходит: Установка TIME_WAIT TCP

После того, как я понял, как заставить все это работать вместе, я решил использовать имитаторы, потому что мое решение показалось мне слишком хакерским на мой вкус.

person Rick    schedule 29.09.2020