Differences between revisions 1 and 2
Revision 1 as of 2020-04-21 13:05:23
Size: 6015
Editor: FrBrGeorge
Comment:
Revision 2 as of 2020-04-21 17:37:28
Size: 8129
Editor: FrBrGeorge
Comment:
Deletions are marked like this. Additions are marked like this.
Line 33: Line 33:

=== Doctest ===
Line 41: Line 43:
 {{{#!python
george@inspiron:~/src/moo> python3 -i Moo.py
 {{{#!highlight pycon
$ python3 -i Moo.py
Line 82: Line 84:
george@inspiron:~/src/moo> python3 -m doctest Moo.py $ python3 -m doctest Moo.py
Line 98: Line 100:
george@inspiron:~/src/moo> python3 -m doctest -v Moo.py $ python3 -m doctest -v Moo.py
Line 140: Line 142:

Тестирование исключений:
{{{#!highlight pycon
$ python -im Moo
>>> moo("QQ")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/george/src/tests/Moo.py", line 33, in moo
    return "M"+"o"*moos+end
TypeError: can't multiply sequence by non-int of type 'str'
>>>
}}}

Как обычно, добавим ''просто весь вывод''!
{{{#!python
def moo(oos=2, end=""):
    '''Издать мычание длиной oos с end в конце
...

Здесь должно быть исключение:
>>> moo("QQ")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/george/src/tests/Moo.py", line 33, in moo
    return "M"+"o"*moos+end
TypeError: can't multiply sequence by non-int of type 'str'
'''
}}}

Вообще говоря, важны только три строчки, остальные можно выкинуть
{{{
...
Здесь должно быть исключение:
>>> moo("QQ")
Traceback (most recent call last):
TypeError: can't multiply sequence by non-int of type 'str'
...
}}}

Тесты должны пройти!

[[py3doc:/doctest.html#simple-usage-checking-examples-in-a-text-file|Перенос тестов во внешний файл]]
 
Пишем файл ( <!> можно в `.rst`, для Sphinx), например, `exttest.rst`:
{{{#!rst
External test
=============

Using Moo
---------

Start from importing `Moo` module:

        >>> import Moo

Then call `moo`:
        >>> Moo.moo(5)
        'Mooooo'
}}}

К нему запускалку тестов:
{{{#!highlight python
import doctest
doctest.testfile("exttest.rst")
}}}

И запускаем её (ключи как у модуля `pytest`):
{{{#!console
$ python3 exttest.py -v
Trying:
    import Moo
Expecting nothing
ok
Trying:
    Moo.moo(5)
Expecting:
    'Mooooo'
ok
1 items passed all tests:
   2 tests in exttest.rst
2 tests in 1 items.
2 passed and 0 failed.
Test passed.

}}}

=== «Серьёзные» фреймворки ===

[[py3doc:unittest]]

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

много теории без питона тут

  • Место тестирования в жизненном цикле программного продукта
    • Собирается — значит, работает!
    • + Проверяется анализатором кода, и потыкано end-user тестерами согласно тест-плану
    • + Автоматическая проверка работоспособности там, где это возможно
    • + Измерение тестового покрытия (coverage)
  • Ручное, автоматизированное, автоматическое
  • Виды тестирования

    • Уровни

      • unit — спецификация компонентов (функций/классов и т. п.)
      • integration — спецификация интерфейсов между компонентами

      • system — спецификация конечного продукта
      • acceptacne — потребительские/рыночные/эксплутационные/… свойства продукта
  • Дисциплина:
    • Сначала весь код, потом некоторые тесты (когда это можно?)
    • Каждая новая фича сопровождается тестом
    • Разработка_через_тестирование (TDD)

      1. сначала пишется тест и заглушка
      2. сам код падает (иначе бесполезен)

      3. под тест пишется код
      4. код не падает
      5. код изменяется и всё равно не падает

  • green test trap: Тестирование может доказать наличие дефектов, но не их отсутствие
  • red test trap: Не всякие проваленные тесты означают дефекты. Могут означать пробел в требованиях, в том числе нефункциональных
  • Полезные ≠ друг другу термины:
    • ошибка программиста при написании программы может привести к

    • дефекту (багу) в программе, который в свою очередь может

    • проявиться (или не проявиться) в виде программного сбоя

  • Стоимость исправления дефекта возрастает пропорционально его «возрасту»
  • Непрерывная интеграция

Модульное тестирование в Python

Doctest

doctest: тест = диалог с python-интерпретатором

  1. Модуль
       1 def moo(oos=2, end=""):
       2     '''Издать мычание длиной oos с end в конце'''
       3     return "M"+"o"*oos+end
    
  2. Тестируем вручную:
       1 $ python3 -i Moo.py
       2 >>> moo()
       3 'Moo'
       4 >>> moo(4)
       5 'Moooo'
       6 >>> moo(0)
       7 'M'
       8 >>> moo(end='!')
       9 'Moo!'
      10 >>> moo(0,'?')
      11 'M?'
      12 
    
  3. Добавляем тесты в docstring:
    def moo(oos=2, end=""):
        '''Издать мычание длиной oos с end в конце
        Оба параметра необязательны:
    >>> moo()
    'Moo'
    
        Первый задаёт количество букв 'o' в слове 'Moo'
    >>> moo(4)
    'Mooooo'
    
        Букв 'o' может и не быть
    >>> moo(0)
    'M'
    
        Второй задаёт символ после всех 'o'
        (по умолчанию — ничего)
    >>> moo(end='!')
    'Moo!'
    >>> moo(0,'?')
    'M?'
    
        '''
        return "M"+"o"*oos+end
  4. Тестирование:
    $ python3 -m doctest Moo.py
    **********************************************************************
    File "/home/george/src/moo/Moo.py", line 13, in Moo.moo
    Failed example:
        moo(4)
    Expected:
        'Mooooo'
    Got:
        'Moooo'
    **********************************************************************
    1 items had failures:
       1 of   5 in Moo.moo
    ***Test Failed*** 1 failures.
  5. Отчёт (с успешными тестами):
    $ python3 -m doctest -v Moo.py
    Trying:
        moo()
    Expecting:
        'Moo'
    ok
    Trying:
        moo(4)
    Expecting:
        'Mooooo'
    **********************************************************************
    File "/home/george/src/moo/Moo.py", line 13, in Moo.moo
    Failed example:
        moo(4)
    Expected:
        'Mooooo'
    Got:
        'Moooo'
    Trying:
        moo(0)
    Expecting:
        'M'
    ok
    Trying:
        moo(end='!')
    Expecting:
        'Moo!'
    ok
    Trying:
        moo(0,'?')
    Expecting:
        'M?'
    ok
    1 items had no tests:
        Moo
    **********************************************************************
    1 items had failures:
       1 of   5 in Moo.moo
    5 tests in 2 items.
    4 passed and 1 failed.
    ***Test Failed*** 1 failures.

Тестирование исключений:

   1 $ python -im Moo
   2 >>> moo("QQ")
   3 Traceback (most recent call last):
   4   File "<stdin>", line 1, in <module>
   5   File "/home/george/src/tests/Moo.py", line 33, in moo
   6     return "M"+"o"*moos+end
   7 TypeError: can't multiply sequence by non-int of type 'str'
   8 >>>
   9 

Как обычно, добавим просто весь вывод!

   1 def moo(oos=2, end=""):
   2     '''Издать мычание длиной oos с end в конце
   3 ...
   4 
   5 Здесь должно быть исключение:
   6 >>> moo("QQ")
   7 Traceback (most recent call last):
   8   File "<stdin>", line 1, in <module>
   9   File "/home/george/src/tests/Moo.py", line 33, in moo
  10     return "M"+"o"*moos+end
  11 TypeError: can't multiply sequence by non-int of type 'str'
  12 '''

Вообще говоря, важны только три строчки, остальные можно выкинуть

...
Здесь должно быть исключение:
>>> moo("QQ")
Traceback (most recent call last):
TypeError: can't multiply sequence by non-int of type 'str'
...

Тесты должны пройти!

Перенос тестов во внешний файл

Пишем файл ( <!> можно в .rst, для Sphinx), например, exttest.rst:

Rendering of reStructured text is not possible, please install Docutils.
External test
=============

Using Moo
---------

Start from importing `Moo` module:

        >>> import Moo

Then call `moo`:
        >>> Moo.moo(5)
        'Mooooo'

К нему запускалку тестов:

   1 import doctest
   2 doctest.testfile("exttest.rst")

И запускаем её (ключи как у модуля pytest):

$ python3 exttest.py -v
Trying:
    import Moo
Expecting nothing
ok
Trying:
    Moo.moo(5)
Expecting:
    'Mooooo'
ok
1 items passed all tests:
   2 tests in exttest.rst
2 tests in 1 items.
2 passed and 0 failed.
Test passed.

«Серьёзные» фреймворки

unittest

TODO

  • unittest
  • py.test , nose
  • tox

  • Показатель покрытия кода тестами (coverage)

TODO pytest/cov

Д/З

  • Осознать, что нуждается в unit-тестировании
  • Оснастить код семестрового проекта unit-тестами (любой фреймворк)
    • Зафиксировать в документации, как их запускать
  • Подумать над тестированием UI
    • например, с помощью порождения событий tkinter

LecturesCMC/PythonDevelopment2020/09_Testing (last edited 2020-04-21 18:44:03 by FrBrGeorge)