The Robot Framework is an automation framework mostly used to create acceptance tests
in the
pytest --cov=<project_name>
or
pytest --cov=backend
pytest --cov=contacts --cov-report=term-missing
pip install pytest pytest-bdd
pip install pytest-cov pytest-benchmark flaky pytest-testmon pytest-xdist
[coverage:run]
source = backend
branch = True
omit =
*/.virtualenvs/*
[coverage:report]
precision = 2
exclude_lines =
pragma: no cover
raise NotImplementedError
raise NotImplemented
ignore_errors = True
[coverage:html]
directory = tests/coverage_html_report
[tool:pytest]
asyncio_mode = auto
minversion = 6.0
addopts =
--cov=backend
--cov=tests
--cov-report=html
testpaths =
tests
filterwarnings = ignore::DeprecationWarning
[tool:mypy]
plugins = strawberry.ext.mypy_plugin,pydantic.mypy
follow_imports = silent
; warn_redundant_casts = True
; warn_unused_ignores = True
; disallow_any_generics = True
check_untyped_defs = True
; no_implicit_reexport = True
; for strict mypy: (this is the tricky one :-))
; disallow_untyped_defs = True
; [pydantic-mypy]
; init_forbid_extra = True
; init_typed = True
; warn_required_dynamic_aliases = True
; warn_untyped_fields = True
https://github.com/nsidnev/fastapi-realworld-example-app/blob/master/pyproject.toml
[tool.pytest.ini_options]
testpaths = "tests"
addopts = '''
--strict-markers
--tb=short
--cov=backend
--cov=tests
--cov-branch
--cov-report=term-missing
--cov-report=html
--no-cov-on-fail
--cov-fail-under=100
'''
filterwarnings = [
"error",
"ignore::UserWarning",
#"ignore::DeprecationWarning",
# note the use of single quote below to denote "raw" strings in TOML
'ignore:function ham\(\) is deprecated:DeprecationWarning',
]
import asyncio
from typing import List
import httpx
import pytest
import pytest_asyncio
from asgi_lifespan import LifespanManager
from motor.motor_asyncio import AsyncIOMotorClient
from bson import ObjectId
from fastapi import status
from chapter6.mongodb.app import app, get_database
from chapter6.mongodb.models import PostDB
motor_client = AsyncIOMotorClient("mongodb://localhost:27017")
database_test = motor_client["chapter9_db_test"]
def get_test_database():
return database_test
@pytest.fixture(scope="session")
def event_loop():
loop = asyncio.get_event_loop()
yield loop
loop.close()
@pytest_asyncio.fixture
async def test_client():
app.dependency_overrides[get_database] = get_test_database
async with LifespanManager(app):
async with httpx.AsyncClient(app=app, base_url="http://app.io") as test_client:
yield test_client
Notice that we used the autouse and scope arguments of the fixture decorator.
autouse
tells pytest to automatically call this fixture even if it's not requested in any test.
In this case, it's convenient because we'll always ensure that the data has been created in the database, without the risk of forgetting to request it in the tests.
scope
, allows us to not run this fixture at the beginning of each test.
With the module
value, the fixture will create the objects only once, at the beginning of this particular test file.
It helps us keep the test fast because in this case, it doesn't make sense to re-create post before each test function.
# p. 280
@pytest_asyncio.fixture(autouse=True, scope="module")
async def initial_posts():
initial_posts = [
PostDB(title="Post 1", content="Content 1"),
PostDB(title="Post 2", content="Content 2"),
PostDB(title="Post 3", content="Content 3"),
]
await database_test["posts"].insert_many(
[post.dict(by_alias=True) for post in initial_posts])
yield initial_posts
await motor_client.drop_database("chapter9_db_test")
from datetime import datetime, timedelta
import unittest
from config import Config
from application.scripts.models import MUser
from application import create_app, mondb
# from application.main_bp import main_routes
import urllib.parse
# print(urllib.parse.quote('asdasda#$@@'))
from flask import url_for
class UserModelCase(unittest.TestCase):
def setUp(self):
self.app = create_app()
# self.app.config['SERVER_NAME'] = 'localhost.localdomain'
# self.app.config.from_object('config.Config')
# self.app = create_app(TestConfig)
self.app_context = self.app.app_context()
self.app_context.push()
# self.client = self.app.test_client(use_cookies=True)
def test_password_hashing(self):
u = MUser(name='susan')
u.set_password('cat')
self.assertFalse(u.check_password('dog'))
self.assertTrue(u.check_password('cat'))
if __name__ == '__main__':
unittest.main(verbosity=2)
Start Locust
locust -f tests_locust.py --host https://asdsadsad.com
# echo 'Process 1'
# celery worker -A celery_worker.celery --loglevel=info
import time
from locust import HttpUser, task, between, SequentialTaskSet, TaskSet
develop_root = 'https://asdasdsad.com'
dev_login = 'https://asdasdsad.com'
dev_contact = 'https://asdasdsad.com'
admin_email = 'sadasd@gmail.com'
admin_password = 'asdasdasda'
user_email = 'sadasd@gmail.com'
user_password = 'asdasd'
# https://docs.locust.io/en/stable/writing-a-locustfile.html#sequentialtaskset-class
class AdminUser(HttpUser):
wait_time = between(5, 8)
@task
class AdminUserTasks(SequentialTaskSet):
# wait_time = between(1, 5)
@task
def first_task(self):
self.client.post('/mongo_login', {
"email": "asdasdd@gmail.ca",
"password": "sadasdsd"
})
# tasks = [function_task]
@task
def second_task(self):
self.client.get("/update_account")
@task
def third_task(self):
self.client.get("/contact")
@task
def third_task(self):
self.client.get("/shop_page")
@task
def logout_task(self):
self.client.get("/logout")
# class AdminUser(HttpUser):
# wait_time = between(1, 5)
# # https://docs.locust.io/en/stable/writing-a-locustfile.html#on-start-and-on-stop-methods
# def on_start(self):
# self.client.post('/mongo_login', {
# "email": "asdasdad@gmail.ca",
# "password": "asdasdad"
# })
# @task
# def index(self):
# self.client.get("/")
# # self.client.get("/static/assets.js")
# @task
# def contact(self):
# self.client.get("/contact")
# @task
# def update_account(self):
# self.client.get("/update_account")
# @task
# def finished_orders(self):
# self.client.get("/finished_orders")
# @task
# def shop_page(self):
# self.client.get("/shop_page")
# @task
# def admin_dashboard(self):
# self.client.get("/admin_dashboard")
# @task
# def admin_dashboard_users(self):
# self.client.get("/admin_dashboard_users")
# class DevelopBranchLive(HttpUser):
# wait_time = between(1, 2)
# @task
# def home_page(self):
# self.client.get('https://www.sadasdas.com')
# self.client.get("/hello")
# self.client.get("/world")
# @task(3)
# def view_item(self):
# for item_id in range(10):
# self.client.get(f"/item?id={item_id}", name="/item")
# time.sleep(1)
# def on_start(self):
# self.client.post("/login", json={"username": "foo", "password": "bar"})
import unittest
from config import Config
from application.scripts.models import MUser, MOrder
from application import create_app
# from application.dashboard_mongo_bp.dashboard_routes import search_orders_template
# import urllib.parse
# print(urllib.parse.quote('asdasda#$@'))
from flask import url_for
import base64
import os.path
from dotenv import load_dotenv
from werkzeug.security import generate_password_hash, check_password_hash
from time import sleep
import re
import time
import json
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from coverage import coverage
basedir = os.path.abspath(os.path.dirname(__file__))
cov = coverage(branch=True,
omit=['test_sheets.py',
'tests.py',
'~/.virtualenvs/*'])
cov.start()
class TestSeleniumBase(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.driver = webdriver.Chrome()
# driver = webdriver.Chrome(executable_path='/chromedriver')
cls.vars = {}
# cls.develop_url = "http://localhost:8080"
cls.develop_url = "http://url.com"
cls.wrong_email = 'asdasdasd@gmail.ca'
cls.admin_email = 'asdasdasd@gmail.ca'
cls.admin_password = 'asdasdad'
cls.user_email = 'asdasdasdasd@gmail.com'
cls.user_password = 'asdasdf'
cls.sleep_time = 0.7
cls.qty_input = '1'
cls.driver.get(cls.develop_url)
@classmethod
def tearDownClass(cls):
cls.driver.quit()
def tearDown(self):
sleep(self.sleep_time)
self.driver.get(self.develop_url + 'logout')
# self.driver.find_element(By.ID, "logout-nav-item").click()
# logout_a_tag = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.ID, "logout-nav-item")))
# logout_a_tag.click()
# sleep(1)
# self.driver.find_element(By.CSS_SELECTOR, "img").click()
# sleep(1)
# self.driver.find_element(By.CSS_SELECTOR, "body").click()
# class TestSeleniumAdminAcct(unittest.TestCase):
class TestSeleniumAdminAcct(TestSeleniumBase):
def setUp(self):
self.driver.get(self.develop_url + 'mongo_login')
# self.driver.maximize_window()
sleep(self.sleep_time)
# # self.driver.implicitly_wait(20)#//gives an implicit wait for 20 seconds
# self.driver.find_element(By.LINK_TEXT, "Login").click()
# self.driver.find_element(By.ID, "login-nav-item").click()
# login_a_tag = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.ID, "login-nav-item")))
# login_a_tag.click()
# sleep(1)
# 4 | click | id=email |
self.driver.find_element(By.ID, "email").click()
sleep(self.sleep_time)
# 5 | type | id=email
self.driver.find_element(By.ID, "email").send_keys(self.wrong_email)
sleep(self.sleep_time)
# 6 | type | id=password |
self.driver.find_element(By.ID, "password").send_keys(self.admin_password)
sleep(self.sleep_time)
# 7 | click | id=submit |
self.driver.find_element(By.ID, "submit").click()
sleep(self.sleep_time)
# 8 | click | id=email |
self.driver.find_element(By.ID, "email").click()
sleep(self.sleep_time)
# 9 | type | id=email
self.driver.find_element(By.ID, "email").send_keys(self.admin_email)
sleep(self.sleep_time)
# 10 | click | id=password |
self.driver.find_element(By.ID, "password").click()
# 11 | type | id=password
self.driver.find_element(By.ID, "password").send_keys(self.admin_password)
sleep(self.sleep_time)
# 12 | click | id=submit |
self.driver.find_element(By.ID, "submit").click()
def test_develop_contact_form(self):
sleep(self.sleep_time)
# 9 | click | linkText=Contact |
self.driver.find_element(By.LINK_TEXT, "Contact").click()
sleep(self.sleep_time)
# 14 | type | id=message | Selenium Contact Page Form from Admin Account
self.driver.find_element(By.ID, "message").send_keys("Selenium Contact Page Form from Admin Account")
sleep(self.sleep_time)
# 15 | click | id=submit |
self.driver.find_element(By.ID, "submit").click()
def test_develop_export_files(self):
sleep(self.sleep_time)
# 9 | click | css=.btn:nth-child(5) > .text-white |
self.driver.find_element(By.CSS_SELECTOR, ".btn:nth-child(5) > .text-white").click()
sleep(self.sleep_time)
# 9 | click | css=.btn:nth-child(4) > .text-white |
self.driver.find_element(By.CSS_SELECTOR, ".btn:nth-child(4) > .text-white").click()
sleep(self.sleep_time)
def test_selenium_develop_checkout(self):
sleep(self.sleep_time)
# 9 | click | linkText=Shop |
self.driver.find_element(By.LINK_TEXT, "Shop").click()
sleep(self.sleep_time)
# 10 | click | id=quantityInputNHW-55 |
self.driver.find_element(By.ID, "quantityInputNHW-55").click()
sleep(self.sleep_time)
# 11 | type | id=quantityInputNHW-55 | 1
self.driver.find_element(By.ID, "quantityInputNHW-55").send_keys("1")
sleep(self.sleep_time)
# 12 | click | css=#memberSectionNHW-55 .ml-4 |
self.driver.find_element(By.CSS_SELECTOR, "#memberSectionNHW-55 .ml-4").click()
sleep(self.sleep_time)
# 13 | click | id=cartSize |
self.driver.find_element(By.ID, "cartSize").click()
sleep(self.sleep_time)
# 14 | select | id=select_idNHW-55 | label=Comapny 1 Person1 McPers Streetsville 22000
dropdown = self.driver.find_element(By.ID, "select_idNHW-55")
dropdown.find_element(By.XPATH, "//option[. = 'Comapny 1 Person1 McPers Streetsville 22000']").click()
sleep(self.sleep_time)
# 15 | mouseDownAt | id=select_idNHW-55 | -1244.25,-240
element = self.driver.find_element(By.ID, "select_idNHW-55")
actions = ActionChains(self.driver)
actions.move_to_element(element).click_and_hold().perform()
sleep(self.sleep_time)
# 16 | mouseMoveAt | id=select_idNHW-55 | -1244.25,-240
element = self.driver.find_element(By.ID, "select_idNHW-55")
actions = ActionChains(self.driver)
actions.move_to_element(element).perform()
sleep(self.sleep_time)
# 17 | mouseUpAt | id=select_idNHW-55 | -1244.25,-240
element = self.driver.find_element(By.ID, "select_idNHW-55")
actions = ActionChains(self.driver)
actions.move_to_element(element).release().perform()
sleep(self.sleep_time)
# 18 | click | id=select_idNHW-55 |
self.driver.find_element(By.ID, "select_idNHW-55").click()
sleep(self.sleep_time)
# 19 | click | css=#complete_checkout > .btn |
self.driver.find_element(By.CSS_SELECTOR, "#complete_checkout > .btn").click()
def test_develop_change_fulfillment_qty(self):
sleep(self.sleep_time)
# 9 | click | name=quantity_number |
# self.driver.find_element(By.NAME, "quantity_number")#.click()
# sleep(self.sleep_time)
# 10 | type | name=quantity_number | 3
self.driver.find_element(By.NAME, "quantity_number").send_keys(self.qty_input)
sleep(self.sleep_time)
# 12 | click | name=down_quantity |
self.driver.find_element(By.NAME, "down_quantity").click()
sleep(self.sleep_time)
# 13 | assertConfirmation | Are you sure you want to update the quantity? |
assert self.driver.switch_to.alert.text == "Are you sure you want to update the quantity?"
sleep(self.sleep_time)
# 14 | webdriverChooseOkOnVisibleConfirmation | |
self.driver.switch_to.alert.accept()
Links: