Тестирование в Django
Тестирование имеет решающее значение в жизненном цикле разработки программного обеспечения, гарантируя, что приложения соответствуют требуемым стандартам качества и функционируют должным образом. Он систематически оценивает программные компоненты, модули или системы для выявления ошибок, багов или отклонений от желаемого поведения.
Тестирование помогает снизить риски, повысить надежность и улучшить общее взаимодействие с пользователем.
Тестирование с Django
Для тестирования в Django необходимо сначала загрузить библиотеку. Чтобы скачать Django, мы используем pip
. В этой статье мы будем использовать pip для управления нашими загрузками на нашем локальном компьютере. Для этого нам нужно запустить команду ниже в нашем терминале:
pip install django
После установки Django создаем проект с django-admin
ключевым словом
django-admin startproject progy .
Это создает базовый шаблон для нашего проекта. Затем мы создаем приложение. Приложение — это автономный модуль или компонент, который инкапсулирует определенную функциональность или функцию веб-приложения. Мы будем называть наше приложение account
.
django-admin startapp account
Это будет выглядеть примерно так после создания.
Далее мы включаем наше приложение INSTALLED APPS
в[settings.py]
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', "account", # our app ]
И в нашу базу urls.py
мы включаем файл URL-адреса приложения.
Примечание. Создайте urls.pyфайл, чтобы избежать ошибок.
from django.contrib import admin from django.urls import path, include url_patterns = [ path('admin/', admin.site.urls), path('', include('account.urls')), ]
Типы тестов
Существуют различные типы тестов, которые обычно выполняются в процессе разработки программного обеспечения, в том числе:
- Модульные тесты: эти тесты сосредоточены на тестировании отдельных модулей или компонентов изолированно.
- Интеграционные тесты: эти тесты проверяют взаимодействие и интеграцию между несколькими модулями.
- Системные тесты: эти тесты проверяют общую функциональность программной системы.
- Приемочные тесты: эти тесты выполняются пользователями или клиентами для проверки того, что программное обеспечение соответствует их требованиям.
Тестирование может выполняться вручную или с использованием автоматизированных сред и инструментов тестирования. Автоматизированное тестирование предпочтительнее в современной разработке программного обеспечения из-за его эффективности, воспроизводимости и масштабируемости.
Это позволяет создавать наборы тестов, которые могут выполняться автоматически, что позволяет разработчикам выявлять проблемы на раннем этапе и оптимизировать процесс разработки.
Тестирование — это не отдельная деятельность в разработке программного обеспечения, а неотъемлемая часть рабочего процесса разработки. Это должно выполняться постоянно на протяжении всего цикла разработки, начиная с ранних стадий сбора требований и проектирования, через реализацию и вплоть до развертывания и обслуживания.
Такой итеративный подход к тестированию обеспечивает быстрое обнаружение и исправление дефектов, что снижает затраты и усилия, связанные с доработкой и исправлением ошибок.
Написание модульных тестов
Написание модульных тестов является фундаментальным аспектом разработки программного обеспечения, и Django предоставляет комплексную среду тестирования, облегчающую этот процесс. Это наиболее распространенная форма теста в Django. Мы рассмотрим тестирование представлений.
Наш views.py
код выглядит следующим образом:
from django.http import HttpResponse def hello_world(request): """A simple view that returns a string "Hello, world!"""" return HttpResponse("Hello, world!") def add_numbers(request): """A view that returns the sum of two numbers.""" if request.method == 'POST': num1 = int(request.POST.get('num1')) num2 = int(request.POST.get('num2')) sum = num1 + num2 return HttpResponse(f"The sum of {num1} and {num2} is {sum}.") else: return HttpResponse("Please submit the form to add two numbers.")
В Django модульные тесты обычно организованы в классы тестовых случаев. Мы создаем новый класс, который наследуется от Django django.test.TestCaseв нашем файле tests.py. Единичные случаи будут основаны на двух функциях, которые у нас есть выше, hello_world и add_numbers соответственно.
Перед этим давайте обновим наше приложение urls.py
from django.urls import path from . import views app_name = 'accounts' urlpatterns = [ path('hello/', views.hello_world, name='hello_world'), path('add/', views.add_numbers, name='add_numbers'), ]
Модульные тесты для этих функций будут выглядеть так:
from django.test import TestCase from django.urls import reverse class HelloWorldViewTest(TestCase): def test_hello_world(self): url = reverse('accounts:hello_world') response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.content.decode(), "Hello, world!") class AddNumbersViewTest(TestCase): def test_add_numbers_get(self): url = reverse('accounts:add_numbers') response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "Please submit the form to add two numbers.") def test_add_numbers_post(self): url = reverse('accounts:add_numbers') data = {'num1': '5', 'num2': '3'} response = self.client.post(url, data) self.assertEqual(response.status_code, 200) self.assertContains(response, "The sum of 5 and 3 is 8.")
Чтобы убедиться, что наши тесты работают и увидеть результат, мы используем команду, python manage.py test
и это дает нам:
Этот процесс создает тестовую базу данных и затем уничтожает ее.
Написание интеграционных тестов
В контексте веб-разработки с Django интеграционные тесты включают проверку взаимодействия между различными частями приложения, такими как представления, модели, шаблоны и база данных.
Для нашего интеграционного теста мы создадим модель models.py
для тестирования.
from django.db import models class Name(models.Model): """A name model.""" name = models.CharField(max_length=100) description = models.TextField() def __str__(self): return self.name
И наш views.py
вернет список имен, которые есть в нашей базе данных.
def name_list(request): """A view that returns a list of names.""" names = Name.objects.all() return render(request, 'account/name_list.html', {'names': names})
The urls.py
from django.urls import path from . import views app_name = 'accounts' urlpatterns = [ path('names/', views.name_list, name='name_list'), ]
И наш интеграционный тест tests.py
будет таким:
from django.test import TestCase, Client from django.urls import reverse from .models import Name class NameIntegrationTest(TestCase): def setUp(self): self.client = Client() self.url = reverse('accounts:name_list') def test_name_list_integration(self): # Create test data Name.objects.create(name='John', description='John Doe') Name.objects.create(name='Jane', description='Jane Smith') # Send a GET request to the URL response = self.client.get(self.url) # Assert the response status code and content self.assertEqual(response.status_code, 200) self.assertContains(response, 'John') self.assertContains(response, 'Jane')
Важно отметить, что интеграционные тесты дополняют модульные тесты, которые фокусируются на изолированном тестировании отдельных модулей или компонентов. Оба типа тестов важны для обеспечения общего качества и надежности программного приложения.
Написание функциональных тестов
Функциональные тесты, также известные как сквозные тесты или приемочные тесты, представляют собой тестирование программного обеспечения, которое проверяет функциональность приложения с точки зрения пользователя. В Django функциональные тесты имитируют взаимодействие пользователя с приложением и проверяют ожидаемое поведение. Используя наш существующий пример из models.py
, views.py
и urls.py
, мы создаем функциональный тест в нашем tests.py
с Selenium в этой статье.
Selenium — это фреймворк с открытым исходным кодом, обычно используемый для автоматизации веб-браузеров. Он предоставляет набор инструментов и библиотек для взаимодействия с веб-браузерами и автоматизации действий браузера, таких как нажатие кнопок, заполнение форм и навигация по веб-страницам. Он также поддерживает множество языков, и Python — один из них.
Наш tests.py
становится
from django.test import LiveServerTestCase from selenium import webdriver from .models import Name from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.by import By class NameFunctionalTest(LiveServerTestCase): def setUp(self): self.selenium = webdriver.Chrome() super().setUp() def tearDown(self): self.selenium.quit() super().tearDown() def test_name_list_functional(self): # Create test data Name.objects.create(name='John', description='John Doe') Name.objects.create(name='Jane', description='Jane Smith') # Simulate user interactions using Selenium self.selenium.get(self.live_server_url + '/names/') self.assertIn('Name List', self.selenium.title) names =self.selenium.find_elements(By.TAG_NAME, 'li') self.assertEqual(len(names), 2) self.assertEqual(names[0].text, 'John - John Doe') self.assertEqual(names[1].text, 'Jane - Jane Smith') # Simulate the page returns a 200 self.assertEqual(self.selenium.title, 'Name List')
После запуска тестовой команды браузер Chrome быстро откроется и выполнит тест.
Тестовое покрытие и отчетность
Покрытие тестами — это мера степени, в которой наш код тестируется нашим набором тестов. Тестовое покрытие необходимо для обеспечения качества и надежности нашего программного обеспечения.
В Django есть различные инструменты для измерения тестового покрытия и создания отчетов. Одним из популярных инструментов является coverage.py
библиотека Python, которая отслеживает, какие части кода выполняются во время выполнения теста.
Чтобы использовать coverage.py
для тестового покрытия и отчетности в Django, давайте выполним следующие шаги.
1. Установите покрытие с помощью pip, выполнив следующую команду
pip install coverage
2. Запустите тесты с покрытием с помощью coverage
команды
coverage run manage.py test
3. После запуска тестов мы можем сгенерировать отчет о покрытии с помощью coverage report
команды. Эта команда показывает сводку покрытия в терминале:
coverage report coverage html # to generate an HTML report that is well detailed
Чтобы настроить покрытие, .coveragerc
можно создать файл конфигурации в корневом каталоге нашего проекта Django. Например, покрытие моего теста для моего кода было:
Тестовые фикстуры и имитация
Тестовые фикстуры и имитация — важные методы тестирования программного обеспечения, которые помогают создавать контролируемые среды и изолировать зависимости для обеспечения надежных и предсказуемых результатов тестирования.
Текстовые фикстуры
Тестовые фикстуры — это набор предопределенных данных, конфигурации или состояний, которые настраиваются перед запуском тестов. Они помогают создать последовательную и известную отправную точку для тестов, позволяя нам воспроизводить определенные условия и поведение. В Django мы можем использовать фикстуры для загрузки данных в нашу тестовую базу данных.
Чтобы создать файл фиксации, мы сначала создаем файл JSON, определяющий тестовые данные, которые мы хотим использовать. Например, давайте создадим sample.json
файл со следующими записями:
[ { "name": "Herlet Skim", "description": "A random person that exists out of nowhere but has a pretty interesting life." }, { "name": "John Doe", "description": "A fictional character who is often used as a placeholder name." }, { "name": "Jane Doe", "description": "A fictional character who is often used as a placeholder name for a woman." }, { "name": "Sherlock Holmes", "description": "A fictional detective created by Sir Arthur Conan Doyle." }, { "name": "Dr. Watson", "description": "A fictional doctor and the partner of Sherlock Holmes." } ]
Получив sample.json
файл, мы можем загрузить фикстуры, используя fixtures
атрибут тестового примера. Указав файл фикстуры в fixtures
атрибуте, Django загрузит тестовые данные, определенные в фикстуре, перед запуском метода тестирования.
from django.test import TestCase class MyTestCase(TestCase): fixtures = ['sample.json'] def test_something(self): # Test logic here
Имитация(mocking)
Имитация, с другой стороны, — это процесс замены реальных объектов или функций специфичными для теста версиями, которые воспроизводят их поведение. В Python/Django unittest.mock
модуль предоставляет мощные возможности имитации.
Чтобы начать работу с mocking, мы импортируем mock
модуль
from unittest.mock import Mock
Используя наши предыдущие данные из models.py
, views.py
и urls.py
, мы создаем новые tests.py
для насмешек
from django.test import TestCase, RequestFactory from unittest.mock import Mock, patch from .models import Name from .views import name_list class NameListViewTest(TestCase): def setUp(self): self.factory = RequestFactory() def test_name_list_view(self): # Create some sample Name objects Name.objects.create(name='John Doe', description='Description 1') Name.objects.create(name='Jane Smith', description='Description 2') # Create a mock request object request = self.factory.get('/names/') # Create a mock queryset for the Name objects mock_queryset = Mock(spec=Name.objects.all()) mock_queryset.return_value = [ Mock(name='John Doe', description='Description 1'), Mock(name='Jane Smith', description='Description 2') ] # Patch the Name.objects.all() method to return the mock queryset with patch('account.views.Name.objects.all', mock_queryset): # Call the name_list view response = name_list(request) # Assert that the response has the expected status code self.assertEqual(response.status_code, 200) # Assert that the response contains the expected data self.assertContains(response, 'John Doe') self.assertContains(response, 'Jane Smith')
Лучшие практики тестирования
Когда дело доходит до тестирования, следование рекомендациям может значительно повысить эффективность и результативность нашего процесса тестирования. Некоторые из лучших практик тестирования, которые следует учитывать:
1. Начните со стратегии тестирования: определите четкую стратегию тестирования, в которой излагаются цели, задачи и подход к тестированию программного обеспечения. Определите типы тестов, которые необходимо выполнить (модульные тесты, интеграционные тесты и т. д.), определите объем тестирования и установите рекомендации по покрытию тестами.
2. Пишите код, который можно тестировать. Разрабатывайте код так, чтобы его было легко тестировать. Следуйте таким принципам, как SOLID и DRY, чтобы писать модульный, несвязанный и повторно используемый код. Отделите бизнес-логику от представления и внешних зависимостей, что упрощает модульное тестирование.
3. Следуйте шаблону AAA: при написании модульных тестов структурируйте их, используя шаблон Arrange-Act-Assert (AAA). Расположите тестовые данные, задайте необходимые предварительные условия, воздействуйте на тестируемый код и подтвердите ожидаемые результаты или поведение.
4. Тестирование пограничных случаев и граничных условий. Убедитесь, что тесты охватывают широкий спектр сценариев, включая пограничные случаи и граничные условия. Проверяйте входные данные при их минимальных и максимальных значениях, пустых или нулевых значениях и любых особых случаях, которые могут повлиять на поведение кода.
5. Мониторинг покрытия кода. Измеряйте и контролируйте покрытие кода, чтобы убедиться, что тесты адекватно охватывают кодовую базу. Стремитесь к высокому охвату кода, чтобы повысить уверенность в надежности и правильности программного обеспечения.
6. Поддерживайте и обновляйте тесты: обновляйте тесты в соответствии с изменениями в кодовой базе. По мере внесения изменений в приложение пересматривайте и обновляйте тесты соответствующим образом. Устаревшие тесты могут давать ложноположительные или ложноотрицательные результаты, что приводит к недостоверным результатам.
Автоматизация тестирования и непрерывная интеграция
Автоматизация тестирования и непрерывная интеграция являются ключевыми методами разработки программного обеспечения, помогающими повысить эффективность, качество и надежность. Рассмотрим эти два понятия более подробно.
Автоматизация тестирования
Это включает в себя использование инструментов и сценариев для автоматизации выполнения тестов, сокращения ручных операций и обеспечения более быстрого и частого тестирования. Он включает в себя написание кода для автоматизации настройки, выполнения и проверки тестовых случаев. Некоторые из преимуществ автоматизации тестирования включают в себя:
1. Повышенная эффективность: автоматизированные тесты могут выполняться намного быстрее по сравнению с ручными тестами, что позволяет быстрее получать обратную связь о качестве программного обеспечения.
2. Увеличение охвата тестами. Благодаря автоматизации тестирования становится проще достичь высокого охвата тестами, выполняя большее количество тестов в более короткие сроки.
3. Интеграция с CI/CD. Автоматизированные тесты можно легко интегрировать в конвейер CI/CD, обеспечивая непрерывное тестирование и более быструю доставку программного обеспечения.
4. Согласованность. Автоматизированные тесты обеспечивают последовательное выполнение тестов и исключают человеческие ошибки, которые могут возникнуть при ручном тестировании.
Популярные среды и инструменты автоматизации тестирования для Django включают unittest , pytest , Selenium , WebDriver для автоматизации браузера и встроенную среду тестирования Django.
Непрерывная интеграция (CI)
Непрерывная интеграция — это практика разработки, при которой разработчики часто объединяют свои изменения кода в общий репозиторий. Процесс CI включает в себя автоматическое создание и тестирование программного обеспечения при каждой фиксации кода. Некоторые из ключевых аспектов CI:
1. Автоматизированная сборка: системы CI автоматически создают программное обеспечение при каждой фиксации кода, гарантируя, что кодовая база остается в согласованном и функциональном состоянии.
2. Автоматизированное тестирование. Автоматизированные тесты, включая модульные тесты, интеграционные тесты и даже тесты пользовательского интерфейса, выполняются как часть процесса CI. Это гарантирует, что изменения кода не приведут к регрессии или нарушению существующей функциональности.
3. Интеграция с контролем версий: системы CI интегрированы с системами контроля версий, такими как Git, что позволяет им отслеживать изменения кода и автоматически запускать процесс сборки и тестирования.
4. Готовность к развертыванию: CI помогает гарантировать, что программное обеспечение всегда находится в состоянии, пригодном для развертывания. Если сборка и тесты проходят успешно, программное обеспечение готово к развертыванию.
Популярные инструменты CI включают Jenkins, Travis CI, CircleCI и GitLab CI/CD.
Сочетая автоматизацию тестирования и непрерывную интеграцию, мы можем создать надежный и эффективный процесс разработки программного обеспечения. Автоматизированные тесты также обеспечивают быструю обратную связь об изменениях кода, обнаруживают проблемы на раннем этапе и улучшают общее качество программного обеспечения.
Заключение
Тестирование является важным аспектом цикла разработки программного обеспечения, поскольку оно помогает обеспечить качество кода, его надежность и правильность.
Применяя комплексный подход к тестированию в наших проектах Django, мы можем улучшить стабильность, ремонтопригодность и общее качество наших приложений.
Это помогает разработчикам создавать продукты, которые соответствуют ожиданиям пользователей, соответствуют спецификациям и выдерживают сценарии реального использования.
Включая методы тестирования в свои рабочие процессы разработки, группы разработчиков программного обеспечения могут добиться более высокого уровня гарантии качества и уровня удовлетворенности клиентов.