Используются для контроля доступа к атрибутам класса. Они позволяют вам добавлять логику при получении (геттер) и изменении (сеттер) значений атрибутов. В Python эти методы можно реализовать с помощью функции
property, которая упрощает создание геттеров и сеттеров, делая код более читабельным и идиоматичным.Геттер — это метод, который возвращает значение атрибута, а сеттер — метод, который устанавливает значение атрибута.
Пример без использования
propertyclass MyClass:
def __init__(self, value):
self._value = value # Приватный атрибут
def get_value(self):
return self._value
def set_value(self, value):
if value >= 0:
self._value = value
else:
raise ValueError("Value must be non-negative")
# Примеры использования
obj = MyClass(10)
print(obj.get_value()) # Вывод: 10
obj.set_value(20)
print(obj.get_value()) # Вывод: 20
try:
obj.set_value(-10) # Пример вызова исключения
except ValueError as e:
print(e) # Вывод: Value must be non-negative
Можно использовать функцию
property, чтобы избежать явных вызовов геттеров и сеттеров и сделать код более естественным и читаемым. property позволяет определить методы доступа как атрибуты.Пример с использованием
propertyclass MyClass:
def __init__(self, value):
self._value = value
@property
def value(self):
return self._value
@value.setter
def value(self, value):
if value >= 0:
self._value = value
else:
raise ValueError("Value must be non-negative")
# Примеры использования
obj = MyClass(10)
print(obj.value) # Вывод: 10 (используется геттер)
obj.value = 20
print(obj.value) # Вывод: 20 (используется сеттер)
try:
obj.value = -10 # Пример вызова исключения через сеттер
except ValueError as e:
print(e) # Вывод: Value must be non-negative
Позволяет скрыть реализацию и управлять доступом к данным через методы, что делает код более безопасным и гибким.
Код выглядит как работа с обычными атрибутами, а не методами, что упрощает его понимание.
Легко добавить валидацию или логику при установке или получении значений.
Также можно использовать декоратор
@property для создания делетера (удаления атрибута).class MyClass:
def __init__(self, value):
self._value = value
@property
def value(self):
return self._value
@value.setter
def value(self, value):
if value >= 0:
self._value = value
else:
raise ValueError("Value must be non-negative")
@value.deleter
def value(self):
del self._value
# Примеры использования
obj = MyClass(10)
print(obj.value) # Вывод: 10
obj.value = 20
print(obj.value) # Вывод: 20
del obj.value
try:
print(obj.value) # Ошибка, так как атрибут удален
except AttributeError as e:
print(e) # Вывод: 'MyClass' object has no attribute '_value'
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥10
Использование оператора
with является рекомендованным способом гарантированного закрытия файла, так как он автоматически управляет открытием и закрытием ресурса. Однако, если по какой-то причине вы не можете использовать with, можно гарантировать закрытие файла другими способами, такими как использование явного вызова метода close() в блоке finally.Открытие и закрытие файла с использованием блока
try-finally гарантирует, что файл будет закрыт, даже если в блоке try произойдет исключение. В этом примере файл открывается в блоке try, и его содержимое читается. Независимо от того, происходит ли исключение в блоке try или нет, блок finally будет выполнен, и файл будет закрыт.file = None
try:
file = open('example.txt', 'r')
content = file.read()
print(content)
finally:
if file:
file.close()
Вы можете создать свой собственный контекстный менеджер, используя классы, который будет управлять открытием и закрытием файла. Это более сложный подход, но он полезен для понимания внутренних механизмов.
class FileManager:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
self.file = None
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_value, traceback):
if self.file:
self.file.close()
# Примеры использования
file_manager = FileManager('example.txt', 'r')
try:
file = file_manager.__enter__()
content = file.read()
print(content)
finally:
file_manager.__exit__(None, None, None)
Еще один способ — использование декоратора для автоматического управления открытием и закрытием файла.
from functools import wraps
def open_file(filename, mode):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
file = open(filename, mode)
try:
result = func(file, *args, **kwargs)
finally:
file.close()
return result
return wrapper
return decorator
@open_file('example.txt', 'r')
def read_file(f):
return f.read()
# Примеры использования
print(read_file())
Модуль
contextlib предоставляет полезные утилиты для создания контекстных менеджеров. Одной из таких утилит является contextlib.contextmanager, которая позволяет создавать контекстные менеджеры с помощью генераторов.from contextlib import contextmanager
@contextmanager
def open_file(filename, mode):
file = open(filename, mode)
try:
yield file
finally:
file.close()
# Примеры использования
file_manager = open_file('example.txt', 'r')
file = file_manager.__enter__()
try:
content = file.read()
print(content)
finally:
file_manager.__exit__(None, None, None)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍11🔥2💊1
Monkey patching (буквально "заплатка обезьяны") в программировании — это техника, позволяющая динамически изменять или расширять код во время выполнения программы. В Python это означает изменение или дополнение методов, атрибутов или классов в модуле или библиотеке, даже если у вас нет прямого доступа к исходному коду.
Быстрое исправление ошибок в сторонних библиотеках без необходимости изменения их исходного кода.
Расширение возможностей сторонних библиотек.
Замена существующих функций или методов на свои собственные для изменения поведения программы.
import time
# Оригинальная функция
def original_sleep(seconds):
time.sleep(seconds)
print(f"Slept for {seconds} seconds")
# Monkey patching функции sleep
def patched_sleep(seconds):
print(f"Patched! Should have slept for {seconds} seconds")
# Применение monkey patching
time.sleep = patched_sleep
# Примеры использования
time.sleep(3) # Вывод: Patched! Should have slept for 3 seconds
Изменения могут быть неочевидны другим разработчикам, что может привести к путанице и затруднениям в отладке.
Monkey patching может вызвать проблемы совместимости при обновлении библиотек или модулей.
Изменения в поведении программы могут быть трудно предсказуемыми и отлаживаемыми.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Это популярный фреймворк для тестирования на языке Python. Он используется для написания и выполнения тестов, чтобы гарантировать, что код работает правильно.
Позволяет выявить ошибки и дефекты на ранних стадиях разработки
Обеспечивает уверенность, что изменения в коде не приводят к новым ошибкам.
Тесты могут служить примером использования кода и его поведения.
Тесты пишутся в виде функций, начинающихся с
test_.Тесты выполняются с помощью команды
pytest в командной строке.Используются стандартные утверждения (
assert) для проверки условий.pytest автоматически находит тестовые функции, классы и файлы.Позволяет запускать один и тот же тест с различными входными данными.
Расширяют функциональность фреймворка, например, для генерации отчетов, интеграции с CI/CD системами.
# test_sample.py
def test_addition():
assert 1 + 1 == 2
def test_subtraction():
assert 2 - 1 == 1
Запуск тестов:
pytest
Фикстуры позволяют подготовить необходимые данные или состояния для тестов.
import pytest
@pytest.fixture
def sample_data():
return {"key1": "value1", "key2": "value2"}
def test_sample_data(sample_data):
assert sample_data["key1"] == "value1"
Позволяет запускать один тест с разными наборами данных.
import pytest
@pytest.mark.parametrize("a, b, result", [
(1, 2, 3),
(2, 3, 5),
(3, 5, 8)
])
def test_addition(a, b, result):
assert a + b == result
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Это объект, который имитирует поведение реального объекта в контролируемом и предсказуемом виде. В контексте тестирования, особенно в Python, это используется для создания фиктивных объектов, которые замещают реальные компоненты системы во время выполнения тестов.
Позволяет тестировать компоненты системы независимо от других частей.
Можно моделировать ответы и поведение зависимостей, таких как базы данных или веб-сервисы.
Тесты с mock-объектами выполняются быстрее, так как не требуют взаимодействия с реальными ресурсами.
Легко симулировать ошибки и исключения, которые сложно воспроизвести с реальными объектами.
Могут заменять любые объекты в коде.
Указание, какие значения должны возвращать mock-объекты.
Возможность проверять, как и сколько раз были вызваны методы mock-объекта.
Упрощают замену объектов в тестах на mock.
Предположим, у нас есть функция, которая обращается к внешнему API:
import requests
def get_user_data(user_id):
response = requests.get(f"https://api.example.com/users/{user_id}")
return response.json()
Чтобы протестировать эту функцию без реальных запросов, можно использовать mock:
from unittest.mock import patch
@patch('requests.get')
def test_get_user_data(mock_get):
mock_get.return_value.json.return_value = {"id": 1, "name": "John Doe"}
result = get_user_data(1)
assert result == {"id": 1, "name": "John Doe"}
mock_get.assert_called_once_with("https://api.example.com/users/1")
return_valueУстанавливает возвращаемое значение метода.
side_effectУстанавливает последовательность возвращаемых значений или исключений.
assert_called_with()Проверяет, что метод был вызван с определенными аргументами.
assert_called_once_with()Проверяет, что метод был вызван ровно один раз с определенными аргументами.
import requests
from unittest.mock import patch
def get_status_code(url):
response = requests.get(url)
return response.status_code
def test_get_status_code():
with patch('requests.get') as mock_get:
mock_get.return_value.status_code = 200
assert get_status_code("https://example.com") == 200
mock_get.assert_called_once_with("https://example.com")
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤5🔥1
Существует несколько видов тестов, каждый из которых имеет свою цель и особенности.
Проверка работы отдельных модулей или функций в изоляции от других частей системы.
Ориентированы на минимальные части кода (функции, методы, классы).
Высокая скорость выполнения.
Простота написания и отладки.
Обычно пишутся разработчиками.
def add(a, b):
return a + b
def test_add():
assert add(1, 2) == 3
Проверка взаимодействия между различными модулями или компонентами системы.
Тестируют комбинации модулей и их взаимодействие.
Более сложные и медленные по сравнению с юнит-тестами.
Могут выявить проблемы в интерфейсах между модулями.
def fetch_data_from_api():
response = requests.get('https://api.example.com/data')
return response.json()
def test_fetch_data_from_api():
data = fetch_data_from_api()
assert 'key' in data
Проверка всей системы целиком на соответствие требованиям.
Тестируют систему в рабочей среде.
Включают проверку всех функциональных и нефункциональных требований.
Могут включать пользовательские сценарии.
Тестирование веб-приложения на основе реальных пользовательских сценариев, включая проверку интерфейса, баз данных и API.
Проверка соответствия системы требованиям и ожиданиям заказчика или конечного пользователя.
Часто выполняются вместе с заказчиком или пользователем.
Фокусируются на бизнес-требованиях и пользовательских сценариях.
Успешное прохождение приемочных тестов является критерием готовности системы к выпуску.
Тестирование нового функционала с участием конечных пользователей для проверки его удобства и соответствия их ожиданиям.
Убедиться, что изменения в коде не вызвали новых ошибок в уже работающем функционале.
Выполняются после внесения изменений в код.
Обычно автоматизируются и включают повторное выполнение всех или части существующих тестов.
Повторное выполнение всех юнит-тестов и интеграционных тестов после рефакторинга кода.
Проверка нефункциональных аспектов системы, таких как производительность, безопасность, удобство использования и др.
Измеряют скорость выполнения, пропускную способность и время отклика системы.
Оценивают защищенность системы от угроз и атак.
Проверяют удобство и интуитивность пользовательского интерфейса.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤1
Это концепция, предложенная Майком Коэном (Mike Cohn), которая описывает оптимальное соотношение разных видов тестов для обеспечения качественного программного обеспечения. Пирамида тестирования визуально представлена в виде треугольника, где каждый уровень соответствует определённому виду тестов, а ширина уровня отражает рекомендуемое количество тестов этого вида.
Расположение: Основание пирамиды.
Цель: Тестирование отдельных функций или методов в изоляции.
Количество: Наибольшее количество тестов.
Особенности: Высокая скорость выполнения, низкая стоимость написания и поддержки.
def add(a, b):
return a + b
def test_add():
assert add(1, 2) == 3
Расположение: Средний уровень пирамиды.
Цель: Тестирование взаимодействия между различными модулями или компонентами.
Количество: Меньше, чем юнит-тестов, но больше, чем системных тестов.
Особенности: Проверка интерфейсов и взаимодействия между модулями, более сложные и медленные, чем юнит-тесты.
def fetch_data_from_api():
response = requests.get('https://api.example.com/data')
return response.json()
def test_fetch_data_from_api():
data = fetch_data_from_api()
assert 'key' in data
Расположение: Вершина пирамиды.
Цель: Тестирование всей системы целиком на соответствие требованиям.
Количество: Наименьшее количество тестов.
Особенности: Включают тестирование пользовательских сценариев, проверку функциональных и нефункциональных требований, самые сложные и медленные.
Юнит-тесты дешевле в написании и выполнении, чем интеграционные и системные тесты.
Большое количество юнит-тестов позволяет быстро находить ошибки на ранних стадиях разработки.
Юнит-тесты способствуют улучшению дизайна кода и повышают его тестируемость.
Хорошее покрытие юнит-тестами позволяет быстро обнаруживать и исправлять ошибки, возникающие после внесения изменений в код.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥2
Такие ситуации можно обработать и протестировать несколькими способами. Один из наиболее распространенных подходов — использование mock-объектов для имитации поведения внешних сервисов. Это позволяет изолировать тестируемую функцию и контролировать ее взаимодействие с внешними сервисами.
С помощью библиотеки
unittest.mock можно подменить вызовы к внешним сервисам и задать их поведение, включая ошибки и исключения.В тестируемой функции следует предусмотреть обработку возможных ошибок, таких как таймауты и HTTP-статусы (например, 404), чтобы она корректно реагировала на эти ситуации.
Предположим, у нас есть функция, которая запрашивает данные с удаленного сервиса
import requests
def fetch_data_from_api(url):
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
return response.json()
except requests.exceptions.Timeout:
return {"error": "Timeout"}
except requests.exceptions.HTTPError as http_err:
return {"error": f"HTTP error: {http_err.response.status_code}"}
except requests.exceptions.RequestException as err:
return {"error": f"Request error: {err}"}
Установка поведения для mock-объекта
Создадим тесты, которые подменяют вызов
requests.get и задают различные сценарии ошибок.from unittest.mock import patch
import requests
import pytest
def test_fetch_data_timeout():
with patch('requests.get') as mock_get:
mock_get.side_effect = requests.exceptions.Timeout
result = fetch_data_from_api("https://example.com/data")
assert result == {"error": "Timeout"}
def test_fetch_data_404():
with patch('requests.get') as mock_get:
mock_response = mock_get.return_value
mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError(response=mock_response)
mock_response.status_code = 404
result = fetch_data_from_api("https://example.com/data")
assert result == {"error": "HTTP error: 404"}
def test_fetch_data_request_exception():
with patch('requests.get') as mock_get:
mock_get.side_effect = requests.exceptions.RequestException("Connection error")
result = fetch_data_from_api("https://example.com/data")
assert result == {"error": "Request error: Connection error"}
Используем
mock_get.side_effect = requests.exceptions.Timeout для имитации ошибки таймаута. Проверяем, что функция возвращает ожидаемое значение при таймауте.Устанавливаем
mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError(response=mock_response) для имитации HTTP ошибки. Устанавливаем код статуса mock_response.status_code = 404. Проверяем, что функция возвращает ожидаемое значение при HTTP ошибке 404.Используем
mock_get.side_effect = requests.exceptions.RequestException("Connection error") для имитации общей ошибки запроса. Проверяем, что функция возвращает ожидаемое значение при общей ошибке запроса.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9😁1
Можно использовать мокирование (mocking) зависимостей или стабирование (stubbing), чтобы заменить долгие операции на быстрые фиктивные реализации, которые будут возвращать заранее заданные значения. Также можно рассмотреть параллельное выполнение или кеширование результатов для ускорения тестов.
Если функция выполняет одинаковые операции с одинаковыми входными данными, можно кэшировать результаты этих операций, чтобы не выполнять их повторно.
Используйте mock-объекты для замены дорогих операций фиктивными, которые возвращают заранее определенные результаты.
Фикстуры позволяют подготовить данные или состояния один раз перед выполнением тестов и повторно использовать их в разных тестах.
Параллельное выполнение тестов может значительно сократить общее время тестирования. Допустим, у нас есть функция, которая выполняет дорогую операцию:
import time
def expensive_operation(data):
time.sleep(5) # Имитация долгой операции
return sum(data)
def process_data(data):
result = []
for item in data:
result.append(expensive_operation(item))
return result
Мы можем замокировать
expensive_operation, чтобы она возвращала заранее определенные результаты без выполнения долгих операций.from unittest.mock import patch
def test_process_data():
data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
with patch('__main__.expensive_operation') as mock_expensive:
mock_expensive.side_effect = [6, 15, 24] # Заранее определенные результаты
result = process_data(data)
assert result == [6, 15, 24]
assert mock_expensive.call_count == 3 # Проверка, что функция вызвана 3 раза
Используем кэширование для хранения результатов дорогостоящих операций.
from functools import lru_cache
@lru_cache(maxsize=None)
def expensive_operation(data):
time.sleep(5) # Имитация долгой операции
return sum(data)
def process_data(data):
result = []
for item in data:
result.append(expensive_operation(tuple(item))) # Преобразуем список в кортеж для кэширования
return result
Фикстуры для подготовки данных
Создаем фикстуры для подготовки данных, которые используются в тестах.
import pytest
@pytest.fixture
def sample_data():
return [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
def test_process_data(sample_data):
with patch('__main__.expensive_operation') as mock_expensive:
mock_expensive.side_effect = [6, 15, 24] # Заранее определенные результаты
result = process_data(sample_data)
assert result == [6, 15, 24]
Запуск тестов параллельно
Используйте возможности параллельного выполнения тестов, например, с помощью
pytest-xdist.pytest -n 4 # Запуск тестов в 4 параллельных потоках
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍8
Проверка взаимодействия между различными модулями или компонентами системы.
Проверяет, как отдельные части системы работают вместе.
Выявляет проблемы, которые могут возникнуть при передаче данных или управлении между модулями.
Проводится после юнит-тестов и перед системными тестами.
Включает взаимодействие с внешними сервисами, базами данных, файлами и другими модулями.
Часто используются mock-объекты для замены реальных зависимостей.
def fetch_data_from_db():
# Имитация запроса к базе данных
return {"user": "John", "email": "john@example.com"}
def send_email(data):
# Имитация отправки электронной почты
print(f"Sending email to {data['email']}")
def process_user_data():
data = fetch_data_from_db()
send_email(data)
Интеграционный тест может выглядеть так
def test_process_user_data():
data = fetch_data_from_db()
assert data["email"] == "john@example.com"
send_email(data)
Проверка функциональности системы на соответствие требованиям.
Проверяет, выполняет ли система свои функции в соответствии с заданными требованиями.
Тестирует систему с точки зрения конечного пользователя.
Может включать юнит-тесты, интеграционные тесты, системные и приемочные тесты.
Не требует знания внутренней структуры или кода системы.
Могут использоваться автоматизированные тестовые фреймворки, такие как Selenium для веб-приложений.
def register_user(username, password):
# Имитация регистрации пользователя
if username and password:
return "Registration successful"
else:
return "Registration failed"
Функциональный тест может выглядеть так:
def test_register_user():
assert register_user("testuser", "securepassword") == "Registration successful"
assert register_user("", "securepassword") == "Registration failed"
Интеграционное тестирование: Проверка взаимодействия между модулями.
Функциональное тестирование: Проверка функциональности системы на соответствие требованиям.
Интеграционное тестирование: Взаимодействие и интерфейсы между модулями.
Функциональное тестирование: Поведение системы с точки зрения пользователя.
Интеграционное тестирование: Промежуточный уровень между юнит-тестами и системными тестами.
Функциональное тестирование: Может охватывать все уровни, включая юнит-тесты, интеграционные, системные и приемочные тесты.
Интеграционное тестирование: Тестирование "серого ящика" (частичное знание внутренней структуры).
Функциональное тестирование: Тестирование "черного ящика" (без знания внутренней структуры).
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
😁7💊4👍3🔥3
Вьюха обрабатывает запрос (например, получение данных из базы данных, выполнение бизнес-логики). На основе обработки данных вьюха формирует объект ответа. В Django это может быть
HttpResponse, JsonResponse и т.д. В Flask это может быть объект Response или просто строка, которая будет конвертирована в ответ. from django.http import HttpResponse
def my_view(request):
data = "Hello, World!"
return HttpResponse(data)
Пример в Flask
from flask import Flask, Response
app = Flask(__name__)
@app.route('/')
def my_view():
return Response("Hello, World!")
После того как вьюха сформировала ответ, он проходит через цепочку промежуточных слоев (middleware). Middleware могут модифицировать объект ответа, добавлять заголовки, обрабатывать ошибки и т.д. Примеры обработки включают логирование, сжатие контента, обработку сессий и т.д.
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
response['X-Custom-Header'] = 'My Custom Header'
return response
После прохождения всех промежуточных слоев ответ передается веб-серверу. Веб-сервер, такой как Nginx или Apache, отправляет сформированный ответ обратно клиенту (например, браузеру). Сервер обрабатывает низкоуровневые детали HTTP-протокола, такие как установка соединения, обработка заголовков и передача данных.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3