Рубрики
Без рубрики

Django: Тестирование того, что, почему и как. (Код)

Это продолжение двух частью серии, пожалуйста, проверьте часть – 1, чтобы посмотреть на теоретическую часть … с меткой Django, Python, Testing, Unittest.

Джанго-тестирование – что-почему-как (2 части серии)

Это продолжение двух частей серии, пожалуйста, проверьте часть-1, чтобы посмотреть на теоретическую часть тестирования.

Оглавление

  1. Охват
  2. Тестирование моделей
  3. Тестирование просмотров
  4. Формы тестирования
  5. Следующие темы для покрытия
  6. Заключение

В этом блоге мы смотрим, как начать с тестирования, а затем о том, как реализовать.

Наша настройка проекта

Охват

Сначала нам нужно знать, что нужно проверить. Как я уже говорил, есть Не нужно тестировать модель Django ‘Vanilla или Django Orm и встроенные функции Python Отказ Именно здесь охват пригодится, это удобный способ для новичка выяснить функции, которые нам нужно проверить.

Как настроить покрытие

Тестирование моделей

Давайте откроем index.html В наших недавно созданных HTMLSCOV Папка в нашем проекте:

Книга библиотеки> HTMLCOV> index.html

Мы увидим что-то вроде этого:

Пойдем к нашему Каталог/Модели .py Отказ

Красная линия показывает линию, нам нужно проверить, и процент представляет, сколько кода было покрыто тестированием.

Учитывая наши Книга модель:

class Book(models.Model):
    """Model representing a book
    """
    title = models.CharField(max_length=200)
    author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
    summary = models.TextField(
        max_length=1000, help_text='Enter a brief description of the book')
    isbn = models.CharField('ISBN', max_length=13, unique=True,
                            help_text='13 Character ISBN number')
    genre = models.ManyToManyField(Genre, help_text='Select a genre for this book', related_name='books')

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        """Returns the url to access a detail record for this book.
        """
        return reverse('book-detail', args=[str(self.id)])

Реализация модели теста

class TestModels(TestCase):
    @classmethod
    def setUpTestData(self):
        thriller = Genre.objects.create(name='thriller')
        scifi = Genre.objects.create(name='scifi')
        book = Book.objects.create(
            title='test title',
            summary='test summary',
            isbn='test isbn',
        )
        book.genre.set([thriller.pk, scifi.pk])

   def test_book_has_genre(self):
        """checks for genres in book
        """
        book = Book.objects.first()
        self.assertEqual(book.genre.count(), 2)

    def test_book_str(self):
        """Checks str for book
        """
        book = Book.objects.first()
        self.assertEqual(str(book), "test title")

    def test_book_absolute_url_with_200(self):
        book = Book.objects.first()
        self.assertEqual(book.get_absolute_url(), '/catalog/book/1')
        response = self.client.get(book.get_absolute_url())
        self.assertEqual(response.status_code, 200)

Тестирование ул

Сначала мы настроим наши данные, а затем мы тестируем на ул ...| представление.

    def test_book_str(self):
        """Checks str for book
        """
        book = Book.objects.first()
        self.assertEqual(str(book), "test title")

Одно следует отметить, что имя метода теста всегда должно начинаться с test_ И это должно быть точным, чтобы можно понять, о чем тест. Однако в случаях, когда вы чувствуете, что именование не может быть точным или значимым, обязательно использовать DocString, чтобы объяснить, что он должен делать.

Тестирование многих для многих

    def test_book_has_genre(self):
        """checks for genres in book
        """
        book = Book.objects.first()
        self.assertEqual(book.genre.count(), 2)

Мы присваивали два жанре для нашей книги, когда мы создаем нашу книгу. Мы просто проверяем подсчет жанров в книге, что говорит нам, что жанры были успешно назначены.

Тестирование абсолютного URL

    def test_book_absolute_url_with_200(self):
        book = Book.objects.first()
        self.assertEqual(book.get_absolute_url(), '/catalog/book/1')
        response = self.client.get(book.get_absolute_url())
        self.assertEqual(response.status_code, 200)

В нашем Книга Модель у нас есть метод под названием get_absolute_url который получает информацию о одной книге. Мы проверяем, будет ли код состояния 200 и get_absolute_url Метод на самом деле является правильным URL.

Тестирование просмотров

Чтобы подтвердить наши взгляды, мы будем использовать Тестовый клиент Django . Примечание: Это не строго «тест на единицу». На самом деле довольно сложно написать независимый тест подразделения для кода просмотра Django.

Мы можем проверить несколько вещей на наших взглядах, но это некоторые общие.

  1. Проверьте, могут ли только зарегистрированные пользователю пользователя, могут авторизовать ваше представление (если пользователь должен войти в систему для доступа).
  2. Проверьте, может ли правильный пользователь авторизовать ваше представление.
  3. Проверьте, если оба Получить и Пост работает так, как он должен.
  4. Проверьте наличие проверки, которую вы могли бы реализовать.

Мы будем ссылаться на нашу Индекс Вид на наше тестирование.

from .models import Book, Author, BookInstance, Genre
from django.contrib.auth.decorators import login_required

@login_required(login_url='/login/')
def index(request):
    """View function for home page of site."""

    # Generate counts of some of the main objects
    num_books = Book.objects.all().count()
    num_instances = BookInstance.objects.all().count()

    # Available books (status = 'a')
    num_instances_available = BookInstance.objects.filter(status__exact='a').count()
    num_authors = Author.objects.count()

    # Number of visits to this view, as counted in the session variable.
    num_visits = request.session.get('num_visits', 0)
    request.session['num_visits'] = num_visits + 1

    context = {
        'num_books': num_books,
        'num_instances': num_instances,
        'num_instances_available': num_instances_available,
        'num_authors': num_authors,
        'num_visits': num_visits,
    }

    # Render the HTML template index.html with the data in the context variable
    return render(request, 'index.html', context=context)

Просмотр просмотра

from django.test import TestCase
from catalog.models import Author
from django.urls import reverse
from django.contrib.auth.models import User
from model_bakery import baker


class IndexViewTest(TestCase):
    @classmethod
    def setUpTestData(cls):
        User.objects.create_user(username='test_user', password='test_password')
        books = baker.make('catalog.Book', _quantity=10)

    def test_view_deny_anonymous(self):
        """Test the view for unauthenticated user if unauthenticated will redirect to login page
        """
        response = self.client.get('/catalog/')
        self.assertRedirects(response, '/login/?next=/catalog/')
        response = self.client.post('/catalog/')
        self.assertRedirects(response, '/login/?next=/catalog/')

    def test_view_url_accesible_by_name(self):
        """Test view is accesible by the reverse method
        """
        self.client.login(username='test_user', password='test_password')
        response = self.client.get(reverse('index'))
        self.assertEqual(response.status_code, 200)
        response = self.client.post(reverse('index'))
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template_(self):
        """Test view is using correct template
        """
        self.client.login(username='test_user', password='test_password')
        response = self.client.get(reverse('index'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'index.html')

    def test_view_has_context_num_books(self):
        self.client.login(username='test_user', password='test_password')
        response = self.client.get(reverse('index'))
        self.assertEqual(response.status_code, 200)
        self.assertTrue('num_books' in response.context)
        self.assertEqual(response.context['num_books'], 10)

Откажитесь от несанкционированного пользователя

    def test_view_deny_anonymous(self):
        """Test the view for unauthenticated user if unauthenticated will redirect to login page
        """
        response = self.client.get('/catalog/')
        self.assertRedirects(response, '/login/?next=/catalog/')
        response = self.client.post('/catalog/')
        self.assertRedirects(response, '/login/?next=/catalog/')

Мы проверяем, запрещено ли неаутентифицированный пользователь и перенаправлен на страницу входа в систему.

URL доступ к имени

    def test_view_url_accessible_by_name(self):
        """Test view is accessible by the reverse method
        """
        self.client.login(username='test_user', password='test_password')
        response = self.client.get(reverse('index'))
        self.assertEqual(response.status_code, 200)
        response = self.client.post(reverse('index'))
        self.assertEqual(response.status_code, 200)

Мы проверяем, если обратный Метод работает и получает нам код состояния 200 для обоих Получить и Пост метод.

Правильный шаблон использования

    def test_view_uses_correct_template_(self):
        """Test view is using correct template
        """
        self.client.login(username='test_user', password='test_password')
        response = self.client.get(reverse('index'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'index.html')

Это проверяет, используется ли правильный шаблон с использованием AssertTemplate Dound метод.

Тест num_books.

    def test_view_has_context_num_books(self):
        self.client.login(username='test_user', password='test_password')
        response = self.client.get(reverse('index'))
        self.assertEqual(response.status_code, 200)
        self.assertTrue('num_books' in response.context)
        self.assertEqual(response.context['num_books'], 10)

В этом методе мы проверяем, если количество книг назначается правильно. Мы используем Модель-пекарня здесь, чтобы создать 10 Книга экземпляры.

Формы тестирования

Формы – это то, что можно легко протестировать единицы. Мы можем проверить проверку в формах. Они принимают словарь значений, подтверждают его и верните ошибки или очищенные данные. В нашем проекте у нас нет формы, поэтому давайте сделаем один ради этого ученика.

from django import forms
from .models import Book


class AddBookForm(forms.ModelForm):
    class Meta:
        model = Book
        fields = ["title"]

    def clean_title(self):
        title = self.cleaned_data['title']
        if not title:
            return title
        if not title[0].isupper():
            self.add_error("title", "Should start with an uppercase")
        if title.endswith("."):
            self.add_error("title", "Should not end with a full stop")

        return title

Мы включили некоторую проверку в нашей модели, которую мы будем тестировать.

Наше тестирование будет выглядеть что-то подобное.

from django.test import TestCase
from catalog.forms import AddBookForm


class AddBookFormTests(TestCase):
    def test_title_starting_lowercase(self):
        form = AddBookForm(data={"title": "a lowercase title"})

        self.assertEqual(
            form.errors["title"], ["Should start with an uppercase"]
        )

    def test_title_ending_full_stop(self):
        form = AddBookForm(data={"title": "A stopped title."})

        self.assertEqual(
            form.errors["title"], ["Should not end with a full stop"]
        )

    def test_title_with_ampersand(self):
        form = AddBookForm(data={"title": ""})

        self.assertEqual(
            form.errors["title"], ["This field is required."]
        )

Как мы можем видеть в формах, мы в основном тестируем для проверки. Если мы хотим добавить некоторые тесты интеграции рядом с тестом единицы, мы могли бы проверить проверку, используя с помощью клиента, делая что-то вроде этого:

    def test_title_starting_lowercase(self):
        response = self.client.post(
            "/books/add/", data={"title": "a lowercase title"}
        )

        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertContains(
            response, "Should start with an uppercase letter", html=True
        )

Следующие темы для покрытия

Я пытался прикрыть как можно больше в этой серии, но там есть тонны вещей, когда речь идет о тестировании. Я постараюсь прикрыть эти темы в моих предстоящих блогах. Краткий список включает в себя:

  • Непрерывная интеграция : Автоматически запустить все тесты всякий раз, когда сделан новый коммит. Это можно сделать с помощью действий GitHub, Trvis CI, Circle CI.

  • Макет : Это акт замены части приложения, который вы тестируете с фиктивной версией.

  • Pteest : Это система тестирования, как и Неизвестный Отказ Мы также можем использовать это вместо модульный тест

  • Модель пекарни : Мы увидели небольшую реализацию этого в нашем проекте Но больше обсуждать.

  • TDD : Испытание.

Заключение

Чтобы заключить, нет никакого конкретного способа написать свои тесты. Это зависит от проекта, на которой вы работаете или в компании, на которой вы работаете. Каждый может иметь свой собственный способ тестирования своих кодов.

Последний совет, который я могу дать вам, не боясь писать тесты. Да, это может быть запугано сначала Но как только вы начнете написание тестов, вы поймете ваши коды лучше, он будет стимулировать вопрос о том, чтобы подать вопрос о том, чтобы подумать обо всех случаях, когда ваша программа может пойти не так, делает вас лучшим программистом.

Так что это за сегодня, если у вас есть какие-либо вопросы относительно этого, пожалуйста, упомяните это в комментарии или если у вас есть какие-либо другие вопросы, пожалуйста, не стесняйтесь обращаться ко мне на следующих платформах, которые я доступен на твиттер , Github , Linkedin.

Джанго-тестирование – что-почему-как (2 части серии)

Оригинал: “https://dev.to/rabbilyasar/django-testing-the-what-why-and-how-3b8l”