Panel informacyjno-kontrolny (#6) – Puszczanie testów

Panel informacyjno-kontrolny (#6) – Puszczanie testów

Poziom trudności
2.5/5

Brakującym elementem tego panelu jest to, że tak naprawdę nim nie sterujesz. A więc wprowadźmy możliwość sterowania. W tym artykule wykorzystamy wiedzę ze wszystkich części tej serii i będziesz mógł uruchomić testy z wybranego pliku.

Pobieranie informacji o plikach z testami

Do wylistowania nazw plików z testami użyjemy biblioteki os. Podając ścieżkę do folderu z testami metodzie os.walk(),uzyskamy listę znajdujących się w niej plików. Stwórzmy więc klasę w pliku app.py, która będzie obsługiwała tworzenie listy testów:

  1. class ListTest:
  2. def __init__(self):
  3. self.test_list = self.__get_tests()
  4. @staticmethod
  5. def __get_tests():
  6. import os
  7. path = os.path.abspath(os.getcwd())
  8. files = []
  9. for _, _, f in os.walk(path):
  10. for file in f:
  11. if '.py' in file and '.pyc' not in file and 'test_' in file:
  12. files.append(file)
  13. return files
  14. def update_list(self):
  15. self.test_list = self.__get_tests()

Jako ścieżkę (path) używam miejsca, gdzie znajduje się plik startowy (app.py) mojego Flask’a. Jednak wystarczy, że zamienisz ją, na dowolną ścieżkę, gdzie znajdują się pliki z twoimi testami, a klasa będzie dalej działała poprawnie. Aby być pewnym, że znajdziemy tylko pliki, które nas interesują, przyjąłem, że muszą mieć rozszerzenie .py — wykluczając pliki .pyc. Dodatkowo moje testy posiadają w nazwie słowo test_. Jeśli posiadasz inną konwencję nazewnictwa, wystarczy, że wyedytujesz linijkę 14 powyższego kodu. Można użyć tu oczywiście wyrażeń regularnych aby sam warunek był dużo krótszy. Więcej na temat wyrażeń regularnych znajdziesz na poniższej stronie:

Tak przygotowana klasa musi być w jakiś sposób przekazana. Tu wykorzystam sposób z części trzeciej serii Panel informacyjno-kontrolny, czyli przekazanie zmiennych już podczas generowania template

Jeszcze przed wywołaniem metody służącej do generowania strony głównej, inicjalizujemy klasę ListTest(). Nie ma potrzeby tworzyć tego obiektu na nowo przy każdym odświeżaniu strony. W samej metodzie używam list_of_tests.update_list(), który uaktualnia listę plików znajdujących się w danym folderze. Na koniec przekazujemy dane w formie dwóch zmiennych file_list (lista plików) i len (ile plików znajduje się na tej liście):

  1. list_of_tests = ListTest()
  2. @app.route("/")
  3. def hello():
  4. list_of_tests.update_list()
  5. return render_template('index.html', file_list=list_of_tests.test_list, len=len(list_of_tests.test_list))

Obsługa przesłanej listy w panelu

Teraz stwórzmy rozwijaną listę w naszym template’cie index.html. Zacznijmy może od tego, czego potrzebujemy na naszej stronie. Będzie to formularz, który w HTML’u jest obsługiwany za pomocą form. Spięta z nim za pomocą id, rozwijana lista – obsługiwana w HTML’u przez select. A także przycisk wywołujący testy – wykorzystamy tu input:

  1. <select name="name" form="start_test">
  2. {%for i in range(0, len)%}
  3. <option>{{file_list[i]}}</option>
  4. {%endfor%}
  5. </select>
  6. <form action="/" id="start_test">
  7. <input type="submit" value="Start test" />
  8. </form>

Jak widzisz powyżej, generacja listy została obsłużona językiem Jinja. Każda z opcji musi znajdować się pomiędzy <option> a </option>. W momencie przyciśnięcia przycisku formularz wywołuje akcje znajdującą się w argumencie action. Przekazuje w ten sposób wybrane dane z części <select> z kluczem name, gdyż taka została w nim przyjęta nazwa. Jednak nasz kod z perspektywy Flask’a nie jest jeszcze na to gotowy. Musimy wrócić do kodu app.py i obsłużyć dane wysłane z formularza. Poniżej pełen kod pliku index.html:

  1. <html>
  2. <head></head>
  3. <script type=text/javascript src="{{url_for('static', filename='jquery.js') }}"></script>
  4. <body>
  5. <select name="name" form="start_test">
  6. {%for i in range(0, len)%}
  7. <option>{{file_list[i]}}</option>
  8. {%endfor%}
  9. </select>
  10. <form action="/" id="start_test">
  11. <input type="submit" value="Start test" />
  12. </form>
  13. <div id="test_info"> </div>
  14. <script>
  15. setInterval(
  16. function update_values() {
  17. $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
  18. $.getJSON($SCRIPT_ROOT+"/sys_info.json",
  19. function(data) {
  20. var i;
  21. var text = "";
  22. for (i = 0; i < data.len; i++) {
  23. text += data.variable[i] + "<br>";
  24. }
  25. $("#test_info").html(text)
  26. });
  27. },1000)
  28. </script>
  29. </body>
  30. </html>

Uruchamianie testów

Nie będziemy potrzebowali nowej funkcji do obsługi danych z formularza. Wykorzystamy główną metodę, w której generujemy stronę startową. Poniżej pełen kod pliku app.py

  1. import os
  2. import json
  3. from flask import Flask, render_template, request
  4. class TestLogger:
  5. def __init__(self):
  6. self.info_list = self.get_info()
  7. @staticmethod
  8. def get_info():
  9. return os.popen('cat logs/pytest.logs').read()
  10. def list_of_lines(self):
  11. return self.info_list.splitlines()
  12. class ListTest:
  13. def __init__(self):
  14. self.test_list = self.__get_tests()
  15. @staticmethod
  16. def __get_tests():
  17. import os
  18. path = os.path.abspath(os.getcwd())
  19. files = []
  20. for _, _, f in os.walk(path):
  21. for file in f:
  22. if '.py' in file and '.pyc' not in file and 'test_' in file:
  23. files.append(file)
  24. return files
  25. def update_list(self):
  26. self.test_list = self.__get_tests()
  27. app = Flask(__name__)
  28. list_of_tests = ListTest()
  29. @app.route("/", methods=['GET', 'POST'])
  30. def hello():
  31. list_of_tests.update_list()
  32. if request.args.get("name"):
  33. os.popen('pytest ' + request.args.get("name") + ' > logs/pytest.logs')
  34. return render_template('index.html', file_list=list_of_tests.test_list, len=len(list_of_tests.test_list))
  35. @app.route('/sys_info.json')
  36. def sys_info():
  37. test_logger = TestLogger()
  38. list_of_lines = test_logger.list_of_lines()
  39. return json.dumps({"len": len(test_logger.list_of_lines()), "variable": list_of_lines})
  40. if __name__ == "__main__":
  41. app.run(host='0.0.0.0', port=5000)

Jak widzimy wystarczy wyedytować tylko trzy linijki, aby obsłużyć puszczanie testów w naszym panelu. W linijce 43 – dekorator odpowiedzialny za nakierowanie na stronę główną dodajemy argument, który pozwoli na obsługę przysyłanych danych np. z formularzy methods=[‚GET’, ‚POST’]. Kolejno w linijkach 46 i 47 – sprawdzam, czy istnieje przysłany argument z nazwą name. Jeżeli tak to uruchamiam wybrany z listy test używając pyTest’a.

Panel informacyjno kontrolny (#6) – Puszczanie testów image

Tak przygotowany możesz tworzyć bardziej lub mniej rozbudowane panele dla swojego środowiska testowego. Z mojej perspektywy wyczerpałem temat najbardziej podstawowych funkcjonalności takiego panelu. Nie wykluczam powrotu do serii, gdy wpadnę na jakiś pomysł rozwoju tego temu lub na prośbę czytelników.

Dodaj komentarz