[PYTHON] J'ai essayé un test de régression visuelle sur les pages GitHub

motivation

Bonjour @glassmonkey. En parlant de Github Action, CI. Je voulais faire quelque chose en utilisant des images si je voulais faire de l'IC, alors j'ai essayé un simple test de régression visuelle. Je l'ai fait à la hâte, alors j'apprécierais vos opinions et vos impressions.

Qu'est-ce qu'un test de régression visuelle?

L'explication sur le blog de Astamuse était facile à comprendre, je vais donc la citer.

Le test de régression visuelle est un test de régression visuelle, en particulier un test qui prend une capture d'écran et extrait la différence.

En d'autres termes, faire un test de régression visuelle dans l'environnement de Github Action L'image suivante sera générée dans l'environnement virtuel.

Dans cet article

Comment as-tu fais

échantillon

Ceux que j'ai réellement réalisés sont les suivants. https://github.com/glassmonkey/vue-sample/pull/3 Je l'ai ajouté à l'application que j'ai créée pour étudier Vuejs.

Cette fois, je l'ai entouré d'un rectangle afin que les changements soient faciles à comprendre, comme indiqué ci-dessous.

L'image originale Image après modification Image de différence
<img width="600px"# alt="L'image originale" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152938/136950cf-4133-b4c5-badb-6ed751650df1.png "> Image modifiée Image de différence

Exigences

https://github.com/glassmonkey/vue-sample/blob/master/.github/workflows/test.yml#L19-L20


BASE_URL: https://glassmonkey.github.io/vue-sample

DIFF_URL: http://localhost:8080

Tester le contenu

Flux d'essai

Le yml pour les tests est le suivant. https://github.com/glassmonkey/vue-sample/blob/master/.github/workflows/test.yml

name: test

on: pull_request
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1 # ①
      - name: develop run # ②
        run: |
          docker-compose up -d
      - name: run test # ③
        run: |
          cd tests && \
          docker-compose build && \
          docker-compose run app \
        env:
          WINDOW_SIZE: 1024,768
          BASE_URL: https://glassmonkey.github.io/vue-sample/
          DIFF_URL: http://localhost:8080
      - uses: jakejarvis/s3-sync-action@master # ④
        env:
          AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: 'ap-northeast-1'
          SOURCE_DIR: './tests/dist'
          DEST_DIR:  ${{github.repository}}/${{github.sha}}
      - name: post maessage # ⑤
        run: |
          cd tests && bash post.sh
        env:
          S3_PATH: https://${{ secrets.AWS_S3_BUCKET }}.s3-ap-northeast-1.amazonaws.com/${{github.repository}}/${{github.sha}}
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

Les informations d'identification doivent être définies comme suit à partir de settings> secrets sur Github. スクリーンショット 2019-12-02 12.30.20.png

Pour expliquer brièvement

  1. Initialisation
  2. Construisez un environnement virtuel avec le contenu de PR
  3. Créer et exécuter un conteneur pour les tests de régression visuelle
  4. Téléchargez l'image générée vers s3
  5. Publiez l'image sur PR

Cela devient le flux de. J'expliquerai le contenu de l'article en 3 génération d'images et 5 PR.

Génération d'images

La prise de vues de scoon et la génération d'images différentielles sont effectuées ci-dessous. https://github.com/glassmonkey/vue-sample/blob/master/tests/src/main.py

Étant donné que le conteneur à exécuter pour le test cette fois-ci est indépendant de l'application construite localement, le nom de localhost ne peut pas être résolu, je l'ai donc réécrit de force du côté test ci-dessous.

    if "localhost" in url: 
         host_addr = subprocess.run(["ip route | awk 'NR==1 {print $3}'"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).stdout.decode("utf8").rstrip('\n')
         url = url.replace("localhost", host_addr)

À propos des captures d'écran

J'ai fait référence à l'article Exécuter Selenium, Headless Chrome et Python 3 sur Docker. Il convient de noter que les éléments optionnels suivants doivent être ajustés. Surtout en commençant avec du chrome sans tête, j'étais un peu accro au fait qu'il est nécessaire de spécifier la taille de la fenêtre au moment du caractère de départ.

   options.add_argument('--headless')
   options.add_argument('--no-sandbox')
   options.add_argument('--disable-dev-shm-usage')
   options.add_argument('--hide-scrollbars')
   options.add_argument('--window-size={}'.format(os.environ['WINDOW_SIZE']))

Cette fois, j'ai créé l'URL de manière statique sous forme de capture d'écran, comme indiqué ci-dessous, mais j'ai pensé qu'il serait acceptable de la personnaliser de l'extérieur, car il semble que vous puissiez également spécifier l'élément Dom à capturer.

    driver.get(url)
    driver.save_screenshot(filename)

À propos de la génération d'image de différence

J'ai fait référence à l'article ici. J'essaie de générer une image de différence de l'image de capture d'écran avec la fonction suivante.

def diff_images(base_image_path, diff_image_path):
    """
    referer to https://www.pyimagesearch.com/2017/06/19/image-difference-with-opencv-and-python/
    :param base_image_path:
    :param diff_image_path:
    :return:
    """
    # load the two input images
    base_image = cv2.imread(base_image_path)
    diff_image = cv2.imread(diff_image_path)

    # convert the images to grayscale
    grayA = cv2.cvtColor(base_image, cv2.COLOR_BGR2GRAY)
    grayB = cv2.cvtColor(diff_image, cv2.COLOR_BGR2GRAY)

    (score, sub) = compare_ssim(grayA, grayB, full=True)
    sub = (sub * 255).astype("uint8")
    print("SSIM: {}".format(score))
    thresh = cv2.threshold(sub, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
    cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)

    for c in cnts:
        # compute the bounding box of the contour and then draw the
        # bounding box on both input images to represent where the two
        # images differ
        (x, y, w, h) = cv2.boundingRect(c)
        cv2.rectangle(base_image, (x, y), (x + w, y + h), (0, 0, 255), 2)
        cv2.rectangle(diff_image, (x, y), (x + w, y + h), (0, 0, 255), 2)
    cv2.imwrite("/app/dist/base.png ", base_image)
    cv2.imwrite("/app/dist/diff.png ", diff_image)
    cv2.imwrite("/app/dist/sub.png ", sub)

POST à PR

https://github.com/glassmonkey/vue-sample/blob/master/tests/post.sh

Je publie une image téléchargée vers s3 via Api sur Github en utilisant Action à télécharger vers s3. Pour le traitement, j'ai fait référence à jessfraz / shaking-finger-action.

résultat

Il a été déposé en toute sécurité sur ce PR. https://github.com/glassmonkey/vue-sample/pull/3 スクリーンショット 2019-12-02 12.49.26.png

Résumé

J'ai pu faire un simple test de régression visuelle. Comme c'est un gros problème, il peut être possible de le placer correctement dans un autre référentiel comme une action. Je n'avais pas touché correctement Api sur Github, donc je m'inquiétais vraiment de ce qu'il fallait faire avec la publication d'images. J'ai choisi s3 cette fois, mais il y a peut-être une autre approche. J'ai abandonné car l'installation d'Opencv devient compliquée, mais j'ai abandonné le conteneur de test d'alpin parce qu'il est lent, mais j'aimerais le rendre alpin.

Recommended Posts

J'ai essayé un test de régression visuelle sur les pages GitHub
J'ai essayé Kaokore, un ensemble de données japonais classique, sur EfficientNet.
J'ai essayé MLflow sur Databricks
J'ai essayé de créer un environnement serveur qui fonctionne sous Windows 10
J'ai essayé AdaNet pour les données de table
J'ai essayé de créer un pointage de crédit simple avec régression logistique.
J'ai essayé d'utiliser l'API COTOHA (il y a aussi du code sur GitHub)
J'ai essayé Cython sur Ubuntu sur VirtualBox
J'ai essayé d'enregistrer une station sur la plateforme IoT "Rimotte"
J'ai essayé d'installer MySQL sur une machine virtuelle Linux sur OCI Compute
J'ai essayé la détection d'objets avec YOLO v3 (TensorFlow 2.0) sur un processeur Windows!
J'ai écrit un diagramme de configuration du système avec des diagrammes sur Docker
J'ai essayé de vérifier le résultat du test A / B avec le test du chi carré
J'ai essayé l'analyse de régression multiple avec régression polypoly
J'ai essayé de créer un linebot (préparation)
J'ai essayé de jouer au jeu ○ ✕ en utilisant TensorFlow
J'ai essayé de dessiner une ligne en utilisant une tortue
J'ai essayé d'installer Kivy dans un environnement Mac
J'ai essayé un langage fonctionnel avec Python
J'ai créé une API Web
J'ai construit un environnement TensorFlow avec windows10
Comment tester sur une page authentifiée par Django
J'ai essayé d'utiliser pipenv, alors prenez note
J'ai essayé de comparer le cadre d'application Web
J'ai essayé la détection 3D d'une voiture
J'ai réussi le premier test d'implémentation de l'IA [A grade], alors j'ai essayé différentes choses
J'ai essayé le tutoriel TensorFlow (MNIST pour les débutants) sur Cloud9-Classification des images manuscrites-
J'ai essayé de créer un BOT de traduction qui fonctionne avec Discord en utilisant googletrans
J'ai essayé de créer une méthode de super résolution / ESPCN
J'ai essayé de créer une méthode de super résolution / SRCNN ①
J'ai essayé d'exécuter YOLO v3 avec Google Colab
Je ne veux pas passer un test de codage
J'ai essayé de lancer jupyter nteract sur le serveur heroku
[Pythonocc] J'ai essayé d'utiliser la CAO sur un notebook Jupyter
J'ai essayé d'utiliser Pythonect, un langage de programmation de flux de données.
J'ai essayé de lire un fichier CSV en utilisant Python
J'ai essayé de générer une chaîne de caractères aléatoire
J'ai essayé d'ajouter un module Python 3 en C
J'ai essayé de créer une méthode de super résolution / SRCNN ③
J'ai essayé de créer une méthode de super résolution / SRCNN ②
J'ai essayé d'exécuter alembic, un outil de migration pour Python
J'ai essayé l'API de message LINE (line-bot-sdk-python) avec GAE
Créer un environnement d'exécution Python sur IBM i
J'ai essayé d'utiliser la base de données (sqlite3) avec kivy
J'ai essayé de jouer avec la calculatrice avec tkinter
Test automatique de Pipenv + Pytest avec actions Github
J'ai créé un jeu ○ ✕ avec TensorFlow
J'ai fait un peu de recherche sur la classe
Le gars qui a trébuché lorsque Pelican n'a pas pu publier son blog sur les pages Github