Введение в основы Python 7 — Написание тестовых случаев

Python модульный тест

Первые шесть статей для начала работы с основами Python:

Это седьмая и последняя из этой основной вводной серии, в которой кратко рассказывается, как принятьunittestТестовые примеры написания моделей.


тестовая функция

Во-первых, дать код для тестирования, как показано ниже, функции, которая принимает имя и фамилию и возвращает аккуратное имя:

def get_formatted_name(first, last):
    full_name = first + ' ' + last
    return full_name.title()

Простой тестовый код:

first = 'kobe'
last = 'bryant'
print(get_formatted_name(first, last)) # 输出 Kobe Bryant

Модули в стандартной библиотеке PythonunittestПредоставляются инструменты для тестирования кода. Вот значения нескольких существительных:

  • модульный тест: используется для проверки отсутствия проблем с аспектом функции;
  • прецедент: набор модульных тестов, которые вместе проверяют, что функция ведет себя должным образом в различных ситуациях.
  • Тестовый пример полного покрытия: Содержит полный набор модульных тестов, охватывающих все возможные варианты использования функции.

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

Далее мы расскажем, как использоватьunittestПротестируйте код.

Первый — импортunittestмодуль, затем создайте наследованиеunittest.TestCaseclass и напишите ряд методов класса для проверки различных вариантов поведения функции, как показано в следующем коде:

import unittest

class NamesTestCase(unittest.TestCase):
    '''
    测试生成名字函数的类
    '''

    def test_first_last_name(self):
        formatted_name = get_formatted_name('kobe', 'bryant')
        self.assertEqual(formatted_name, 'Kobe Bryant')
        
unittest.main()

Вывод выглядит следующим образом, показывая, что запущен 1 тестовый образец, а потребление времени составляет 0,001 с.

.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

Выше приведен пример, который может пройти, и если тест не пройден, каков результат, как показано ниже:

# 添加中间名
def get_formatted_name(first, middel, last):
    full_name = first + ' ' + middle + ' ' + last
    return full_name.title()

class NamesTestCase(unittest.TestCase):
    '''
    测试生成名字函数的类
    '''
	# 不能通过的例子
    def test_first_name(self):
        formatted_name = get_formatted_name('kobe', 'bryant')
        self.assertEqual(formatted_name, 'Kobe Bryant')
                
unittest.main()

Вывод следующий, где произошла ошибка и будет напечатана причина ошибки:

E
======================================================================
ERROR: test_first_last_middle_name (__main__.NamesTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "E:/Python_Notes/Practise/unittest_practise.py", line 39, in test_first_last_middle_name
    formatted_name = get_formatted_name('kobe', 'bryant')
TypeError: get_formatted_name() missing 1 required positional argument: 'middle'

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)

Видимо из-за отсутствияmiddleПараметры, если вы хотите пройти тест, вы можете изменить исходную функцию следующим образом:

def get_formatted_name(first, last, middle=''):
    '''
    接收姓和名然后返回完整的姓名
    :param first:
    :param last:
    :return:
    '''
    if middle:
        full_name = first + ' ' + middle + ' ' + last
    else:
        full_name = first + ' ' + last
    return full_name.title()

Затем добавьте новый метод тестирования, продолжите выполнение, и тест может быть пройден.

def test_first_last_middle_name(self):
    formatted_name = get_formatted_name('kobe', 'bryant', 'snake')
    self.assertEqual(formatted_name, 'Kobe Snake Bryant')

тестовый класс

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

Метод утверждения

существуетunitest.TestCaseВ классе предусмотрено множество методов утверждения, которые использовались в предыдущем разделе.assertEqualЭто метод утверждения для оценки равенства данных двух параметров.Вот шесть наиболее часто используемых методов утверждения:

метод использовать
assertEqual(a, b) Убедитесь, что а == б
assertNotEqual(a, b) Убедитесь, что а != б
assertTrue(x) убедиться, что x истинно
assertFalse(x) убедиться, что x является False
assertIn(item, list) Убедитесь, что элемент находится в списке
assertNotIn(item, list) Убедитесь, что элемент отсутствует в списке

Эти методы могут быть унаследованы толькоunittest.TestCaseкласс, использующий эти методы.

Пишите тесты против классов

Во-первых, напишите класс для выполнения теста, код выглядит следующим образом, это класс для управления анонимными ответами на анкету:

class AnonymousSurvey():
    '''
    收集匿名调查问卷的答案
    '''

    def __init__(self, question):
        '''

        :param question:
        '''
        self.question = question
        self.responses = []
    
    def show_question(self):
        '''
        显示问卷
        :return: 
        '''
        print(self.question)
    
    def store_response(self, new_response):
        '''
        存储单份调查问卷
        :param new_response: 
        :return: 
        '''
        self.responses.append(new_response)
    
    def show_results(self):
        '''
        显示所有答卷
        :return: 
        '''
        print('Survey results:')
        for response in self.responses:
            print('- ' + response)
   

Этот класс содержит три метода, а именно: отображать вопросы, хранить одну анкету и отображать все анкеты.Вот пример использования:

def use_anonymous_survey():
    question = "世上最好的语言是?"
    language_survey = AnonymousSurvey(question)
    # 显示问题
    language_survey.show_question()
    # 添加问卷
    language_survey.store_response('php')
    language_survey.store_response('python')
    language_survey.store_response('c++')
    language_survey.store_response('java')
    language_survey.store_response('go')
    # 展示所有问卷
    language_survey.show_results()


if __name__ == '__main__':
    use_anonymous_survey()

Результат выглядит следующим образом:

世上最好的语言是?
Survey results:
- php
- python
- c++
- java
- go

Затем начните писать тестовый код для класса, также создайте класс, наследуйтеunittest.TestCase, а затем тестируется метод класса, код выглядит следующим образом:

import unittest

class TestAnonmyousSurvey(unittest.TestCase):

    def test_store_single_response(self):
        '''
        测试保存单份问卷的方法
        :return:
        '''
        question = "世上最好的语言是?"
        language_survey = AnonymousSurvey(question)
        language_survey.store_response('php')

        self.assertIn('php', language_survey.responses)
unittest.main()

В приведенном выше коде используетсяassertInМетоды утверждения для проверки функцийstore_response().

Здесь вы можете продолжить проверку возможности сохранения дополнительных анкет.Как показано ниже, тест хранит три анкеты:

 def test_store_three_response(self):
     question = "世上最好的语言是?"
     language_survey = AnonymousSurvey(question)
     responses = ['c++', 'php', 'python']
     for response in responses:
     	language_survey.store_response(response)

    for response in responses:
    	self.assertIn(response, language_survey.responses)

Наконец, вunittest.TestCaseна самом деле содержит методsetUp(), который действует как метод инициализации класса__init()__, это будет в разныхtest_Первый метод запускается перед запуском, поэтому вы можете создавать объекты в этом методе, чтобы избежать необходимости создавать его снова в каждом тестовом методе, поэтому приведенный выше код можно изменить следующим образом:

class TestAnonmyousSurvey(unittest.TestCase):

    def setUp(self):
        '''
        创建一个调查对象和一组答案
        :return:
        '''
        question = "世上最好的语言是?"
        self.language_survey = AnonymousSurvey(question)
        self.responses = ['c++', 'php', 'python']

    def test_store_single_response(self):
        '''
        测试保存单份问卷的方法
        :return:
        '''
        self.language_survey.store_response(self.responses[1])

        self.assertIn('php', self.language_survey.responses)

    def test_store_three_response(self):
        for response in self.responses:
            self.language_survey.store_response(response)

        for response in self.responses:
            self.assertIn(response, self.language_survey.responses)

После запуска вывод следующий:

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Обратите внимание, что если операция здесь выполнена успешно, печатается точка.Поскольку два метода тестирования успешно выполнены, печатаются две точки, если в операции есть ошибка, печатается точка.E; тест вызывает ошибку утверждения, выводяF.


Ссылаться на

  • «Программирование на Python — от начала к практике»

резюме

Здесь представлена ​​основная вводная часть Python.Первоначальный план первой статьи выглядит следующим образом:

  1. Введение и конфигурация среды
  2. Переменные и простые типы данных
  3. Списки и кортежи
  4. Словарь
  5. если условное выражение
  6. оператор цикла for/while
  7. функция
  8. своего рода
  9. файлы и исключения
  10. тестовый код

Так получилось, что в основном были представлены знания по 10 вышеперечисленным аспектам, и в последующем будут дополнительные точки знаний, включая дополнительные точки знаний о функциях и классах, регулярных выражениях, сетевом программировании, таком как знание процессов и потоков, и резюме или перевод курса Несколько хороших статей, знакомящих с навыками работы с Python и рассказывающих о том, как использовать некоторые распространенные библиотеки, такие как numpy, pandas, matplotlib и т. д.

Конечно, есть также усилия, чтобы сделать несколько интересных проектов.

Примеры кода из этой статьи также загружены на мой Github:

Добро пожаловать в мой общедоступный аккаунт WeChat--Рост алгоритма обезьяны, или отсканируйте QR-код ниже, чтобы общаться, учиться и развиваться вместе!