Este texto está destinado a probadores novatos que desean comprender cómo hacer informes sobre el atractivo con el historial de pruebas, y también explicar dónde almacenarlos para que cualquier miembro de su equipo pueda consultar el informe.

Repositorio de trabajo con infraestructura y código de trabajo final
Enlace a informes después de ejecutar pruebas
gitlab python, allure, docker, , . , , , . allure, . , UI , .
. , . windows, .
, python, , . pytest, , , . Dog API. gitlab, docker.
, :
- Python
- Allure . .
- PyCharm Community
- ssh git gitlab
- Pytest —
- API
- allure
- Gitlab Runner
- .gitlab-ci.yml
- UI
allure_pages .
:

conftest.py—requirements.txt— pythontest_dog_api.pytests
, . :
python -m venv venv
PyCharm

, PyCharm . , .
-
Add Interpreter, PyCharm ,

:
.
pip install requests— , Dog Apipip install pytest— ,pip install pytest-xdist—pip install allure-pytest— allure
pip freeze > requirements.txt.
requirements.txt.
, requirements.txt
allure-pytest==2.8.18 pytest==6.0.1 pytest-xdist==2.1.0 requests==2.24.0
API
, GET POST . . , . .
@pytest.fixture
def dog_api():
return ApiClient(base_address="https://dog.ceo/api/")
. base_address, https://dog.ceo/api/. , GET POST .
class ApiClient:
def __init__(self, base_address):
self.base_address = base_address
GET .
def get(self, path="/", params=None, headers=None):
url = f"{self.base_address}{path}"
return requests.get(url=url, params=params, headers=headers)
, requests. ApiClient path, params, headers get , requests.get(url=url, params=params, headers=headers). . , , , , requests.get.
POST. , , .
def post(self, path="/", params=None, data=None, json=None, headers=None):
url = f"{self.base_address}{path}"
return requests.post(url=url, params=params, data=data, json=json, headers=headers)
conftest.py:
import pytest
import requests
class ApiClient:
def __init__(self, base_address):
self.base_address = base_address
def post(self, path="/", params=None, data=None, json=None, headers=None):
url = f"{self.base_address}{path}"
return requests.post(url=url, params=params, data=data, json=json, headers=headers)
def get(self, path="/", params=None, headers=None):
url = f"{self.base_address}{path}"
return requests.get(url=url, params=params, headers=headers)
@pytest.fixture
def dog_api():
return ApiClient(base_address="https://dog.ceo/api/")
Dog API . , . , . , . , . test_dog_api.py
import pytest
def test_get_random_dog(dog_api):
response = dog_api.get("breeds/image/random")
with allure.step(" , "):
assert response.status_code == 200, f" , {response.status_code}"
with allure.step(" . json ."):
response = response.json()
assert response["status"] == "success"
with allure.step(f" {response}"):
with allure.step(f" "):
with allure.step(f" - "):
pass
@pytest.mark.parametrize("breed", [
"afghan",
"basset",
"blood",
"english",
"ibizan",
"plott",
"walker"
])
def test_get_random_breed_image(dog_api, breed):
response = dog_api.get(f"breed/hound/{breed}/images/random")
response = response.json()
assert breed in response["message"], f" , {response}"
@pytest.mark.parametrize("file", ['.md', '.MD', '.exe', '.txt'])
def test_get_breed_images(dog_api, file):
response = dog_api.get("breed/hound/images")
response = response.json()
result = '\n'.join(response["message"])
assert file not in result, f" {file}"
@pytest.mark.parametrize("breed", [
"african",
"boxer",
"entlebucher",
"elkhound",
"shiba",
"whippet",
"spaniel",
"dvornyaga"
])
def test_get_random_breed_images(dog_api, breed):
response = dog_api.get(f"breed/{breed}/images/")
response = response.json()
assert response["status"] == "success", f" {breed}"
@pytest.mark.parametrize("number_of_images", [i for i in range(1, 10)])
def test_get_few_sub_breed_random_images(dog_api, number_of_images):
response = dog_api.get(f"breed/hound/afghan/images/random/{number_of_images}")
response = response.json()
final_len = len(response["message"])
assert final_len == number_of_images, f" {number_of_images}, {final_len}"
allure
allure. , . , .
with allure.step('step 1'): — , .
@allure.feature('Dog Api') @allure.story('Send few requests') — ,
allure, . allure,
API allure .
class ApiClient:
def __init__(self, base_address):
self.base_address = base_address
def post(self, path="/", params=None, data=None, json=None, headers=None):
url = f"{self.base_address}{path}"
with allure.step(f'POST request to: {url}'):
return requests.post(url=url, params=params, data=data, json=json, headers=headers)
def get(self, path="/", params=None, headers=None):
url = f"{self.base_address}{path}"
with allure.step(f'GET request to: {url}'):
return requests.get(url=url, params=params, headers=headers)
. , . . .
@allure.feature('Random dog')
@allure.story(' ')
def test_get_random_dog(dog_api):
response = dog_api.get("breeds/image/random")
with allure.step(" , "):
assert response.status_code == 200, f" , {response.status_code}"
with allure.step(" . json ."):
response = response.json()
assert response["status"] == "success"
with allure.step(f" {response}"):
with allure.step(f" "):
with allure.step(f" - "):
pass
. test_dog_api.py
import pytest
import allure
@allure.feature('Random dog')
@allure.story(' ')
def test_get_random_dog(dog_api):
response = dog_api.get("breeds/image/random")
with allure.step(" , "):
assert response.status_code == 200, f" , {response.status_code}"
with allure.step(" . json ."):
response = response.json()
assert response["status"] == "success"
with allure.step(f" {response}"):
with allure.step(f" "):
with allure.step(f" - "):
pass
@allure.feature('Random dog')
@allure.story(' ')
@pytest.mark.parametrize("breed", [
"afghan",
"basset",
"blood",
"english",
"ibizan",
"plott",
"walker"
])
def test_get_random_breed_image(dog_api, breed):
response = dog_api.get(f"breed/hound/{breed}/images/random")
with allure.step(" . json ."):
response = response.json()
assert breed in response["message"], f" , {response}"
@allure.feature('List of dog images')
@allure.story(' ')
@pytest.mark.parametrize("file", ['.md', '.MD', '.exe', '.txt'])
def test_get_breed_images(dog_api, file):
response = dog_api.get("breed/hound/images")
with allure.step(" . json ."):
response = response.json()
with allure.step(" "):
result = '\n'.join(response["message"])
assert file not in result, f" {file}"
@allure.feature('List of dog images')
@allure.story(' ')
@pytest.mark.parametrize("breed", [
"african",
"boxer",
"entlebucher",
"elkhound",
"shiba",
"whippet",
"spaniel",
"dvornyaga"
])
def test_get_random_breed_images(dog_api, breed):
response = dog_api.get(f"breed/{breed}/images/")
with allure.step(" . json ."):
response = response.json()
assert response["status"] == "success", f" {breed}"
@allure.feature('List of dog images')
@allure.story(' ')
@pytest.mark.parametrize("number_of_images", [i for i in range(1, 10)])
def test_get_few_sub_breed_random_images(dog_api, number_of_images):
response = dog_api.get(f"breed/hound/afghan/images/random/{number_of_images}")
with allure.step(" . json ."):
response = response.json()
with allure.step(" "):
final_len = len(response["message"])
assert final_len == number_of_images, f" {number_of_images}, {final_len}"
, :
.gitlab-ci.yml— , yaml gitlab runnergitlab-runner— , Go. . . gitlab runner, docker . "". .
devops - , . . docker desktop windows. , .gitlab-ci .
docker desktop, .
, gitlab.com. gitlab.com, . , .
Settings -> General -> Visibility, project features, permissions, Pipelines .

CI / CD. Settings -> CI / CD -> Runners

1 Gitlab Runner. .
Gitlab Runner
, . . .
- - , : C:\GitLab-Runner.
- x86 amd64 . gitlab-runner.exe.
- . ( powershell )
- . , () .
. , powershell, , . , , .
C:\gitlab_runners , gitlab-runner.exe
, :
- :
./gitlab-runner.exe register - url, 2. , :
https://gitlab.somesubdomain.com/ - 3. , :
tJTUaJ7JxfL4yafEyF3k - . UI . :
Runner on windows for autotests - , , .gitlab-ci.yml, . , .
docker, windows - , . docker
docker - image, .
.gitlab-ci.yml
python:3.8-alpine

, .
:
.\gitlab-runner.exe status
:
.\gitlab-runner.exe run
, Settings -> CI / CD -> Runners, - :

, . . .

, .
.gitlab-ci.yml
.gitlab-ci.yml. .
stages. . 4. stage — job, .
stages:
- testing #
- history_copy #
- reports #
- deploy # gitlab pages
. Testing
docker_job: # job
stage: testing # stage,
tags:
- docker # gitlab , . , , 6 .
image: python:3.8-alpine # , .
before_script:
- pip install -r requirements.txt #
script:
- pytest -n=4 --alluredir=./allure-results tests/test_dog_api.py # (-n=4 ), --alluredir=
allow_failure: true # , .
artifacts: # , , .
when: always #
paths:
- ./allure-results #
expire_in: 1 day # , . .
. history_copy
history_job: # job
stage: history_copy # stage,
tags:
- docker #
image: storytel/alpine-bash-curl # , . , ?
script:
- 'curl --location --output artifacts.zip "https://( , gitlab.example.com)/api/v4/projects/( )/jobs/artifacts/master/download?job=pages&job_token=$CI_JOB_TOKEN"' # api job, . .
- apk add unzip # , unzip,
- unzip artifacts.zip #
- chmod -R 777 public #
- cp -r ./public/history ./allure-results #
allow_failure: true # , . .
artifacts:
paths:
- ./allure-results #
expire_in: 1 day
rules:
- when: always #
. reports
allure_job: # job
stage: reports # stage,
tags:
- docker #
image: frankescobar/allure-docker-service # allure. .
script:
- allure generate -c ./allure-results -o ./allure-report # ./allure-results ./allure-report
artifacts:
paths:
- ./allure-results #
- ./allure-report
expire_in: 1 day
rules:
- when: always
. deploy
pages: # job , pages
stage: deploy # stage,
script:
- mkdir public # public. gitlab pages public
- mv ./allure-report/* public # public .
artifacts:
paths:
- public
rules:
- when: always
.gitlab-ci.yml
stages:
- testing #
- history_copy #
- reports #
- deploy # gitlab pages
docker_job: # job
stage: testing # stage,
tags:
- docker # gitlab , . , , 6 .
image: python:3.8-alpine # , .
before_script:
- pip install -r requirements.txt #
script:
- pytest -n=4 --alluredir=./allure-results tests/test_dog_api.py # (-n=4 ), --alluredir=
allow_failure: true # , .
artifacts: # , , .
when: always #
paths:
- ./allure-results #
expire_in: 1 day # , . .
history_job: # job
stage: history_copy # stage,
tags:
- docker #
image: storytel/alpine-bash-curl # , . , ?
script:
- 'curl --location --output artifacts.zip "https://( , gitlab.example.com)/api/v4/projects/( )/jobs/artifacts/master/download?job=pages&job_token=$CI_JOB_TOKEN"' # api job, . .
- apk add unzip # , unzip,
- unzip artifacts.zip #
- chmod -R 777 public #
- cp -r ./public/history ./allure-results #
allow_failure: true # , . .
artifacts:
paths:
- ./allure-results #
expire_in: 1 day
rules:
- when: always #
allure_job: # job
stage: reports # stage,
tags:
- docker #
image: frankescobar/allure-docker-service # allure. .
script:
- allure generate -c ./allure-results -o ./allure-report # ./allure-results ./allure-report
artifacts:
paths:
- ./allure-results #
- ./allure-report
expire_in: 1 day
rules:
- when: always
pages: # job , pages
stage: deploy # stage,
script:
- mkdir public # public. gitlab pages public
- mv ./allure-report/* public # public .
artifacts:
paths:
- public
rules:
- when: always
, :
conftest.py-
tests requirements.txt(, ).gitlab-ci.yml
.
, . , . CI / CD -> Pipelines
, Ci , .gitlab-ci.yml.

, Settings -> Pages. pages 30 . .

. .

, , . .

. , stage history_job . .

, . .

UI
[services](https://docs.gitlab.com/ee/ci/services/). , script. UI job :
services:
- selenium/standalone-chrome:latest
, url, - url, . :
-
: -
/__ -
/-( Gitlab Runner v1.1.0 )
executor ( chromedriver , ) ui :
browser = webdriver.Remote(command_executor="http://selenium__standalone-chrome:4444/wd/hub")
, .gitlab-ci.yml:
selenium/standalone-chrome:latest
:
selenium__standalone-chrome
Para ejecutar mis pruebas, obtuve este trabajo. Si le agrega los siguientes tres trabajos del ejemplo con pruebas de API, entonces puede ejecutar todas las pruebas y obtener un informe.
chrome_job:
stage: testing
services:
- selenium/standalone-chrome
image: python:3.8
tags:
- docker
before_script:
- pip install -r requirements.txt
script:
- pytest --alluredir=./allure-results tests/
allow_failure: true
artifacts:
when: always
paths:
- ./allure-results
expire_in: 1 day
Enlaces útiles
Además de los enlaces del artículo, me gustaría compartir algunos más que pueden ayudar a trabajar con allure y gitlab ci.
Un ejemplo de este proyecto en gitlab
Enlace a informes después de ejecutar pruebas
Un artículo sobre allure en habr
Introducción a gitlab ci
UPD: Gracias a los comentaristas por señalar las inexactitudes y lo incompleto de esta guía. He corregido y agregado un enlace al repositorio de trabajo.