Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Больше СТОПов, больше "Огня"




Больше СТОПов, больше " Огня"

Наряду с тестированием на слишком большой " ввод" необходимо протестировать и слишком маленький. Как было отмечено в требованиях к функциональности, римские цифры не могут быть меньше или равны 0.

> > > import roman2
> > > roman2. to_roman(0)
''
> > > roman2. to_roman(-1)
''

Не хорошо. Добавим тесты для каждого случая.

class ToRomanBadInput(unittest. TestCase):
def test_too_large(self):
'''to_roman should fail with large input'''
self. assertRaises(roman3. OutOfRangeError, roman3. to_roman, 4000) ①

def test_zero(self):
'''to_roman should fail with 0 input'''
self. assertRaises(roman3. OutOfRangeError, roman3. to_roman, 0) ②

def test_negative(self):
'''to_roman should fail with negative input'''
self. assertRaises(roman3. OutOfRangeError, roman3. to_roman, -1) ③

1. Метод test_too_large() не изменился. Я включил его сюда, чтобы показать схожесть кода.

2. Это новый тест: test_zero(). Как и test_too_large(), мы заставляем метод assertRaises(), определенный в unittest. TestCase, вызвать нашу функцию to_roman() с параметром " 0", и проверить, что она выбрасывает соответствующее исключение, OutOfRangeError.

3. Метод test_negative() почти аналогичный, только передает -1 в функцию to_roman(). И ни один из этих методов не вернет ошибку OutOfRangeError (потому что наша функция возвращает значение), и тест считается проваленным.

Теперь проверим, что тест провалится:

you@localhost: ~/diveintopython3/examples$ python3 romantest3. py -v
test_to_roman_known_values (__main__. KnownValues)
to_roman should give known result with known input... ok
test_negative (__main__. ToRomanBadInput)
to_roman should fail with negative input... FAIL
test_too_large (__main__. ToRomanBadInput)
to_roman should fail with large input... ok
test_zero (__main__. ToRomanBadInput)
to_roman should fail with 0 input... FAIL
======================================================================
FAIL: to_roman should fail with negative input
----------------------------------------------------------------------
Traceback (most recent call last):
File " romantest3. py", line 86, in test_negative
self. assertRaises(roman3. OutOfRangeError, roman3. to_roman, -1)
AssertionError: OutOfRangeError not raised by to_roman
======================================================================
FAIL: to_roman should fail with 0 input
----------------------------------------------------------------------
Traceback (most recent call last):
File " romantest3. py", line 82, in test_zero
self. assertRaises(roman3. OutOfRangeError, roman3. to_roman, 0)
AssertionError: OutOfRangeError not raised by to_roman
----------------------------------------------------------------------
Ran 4 tests in 0. 000s
FAILED (failures=2)

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

def to_roman(n):
'''convert integer to Roman numeral'''
if not (0 < n < 4000): ①
raise OutOfRangeError('number out of range (must be 1.. 3999)') ②

result = ''
for numeral, integer in roman_numeral_map:
while n > = integer:
result += numeral
n -= integer
return result

1. Отличный пример сокращения Python: множественное сравнение в одну строку. Это эквивалентно выражению " Если не ((0 < n) и (n < 4000))", но читается проще. Этот однострочный код охватывает " плохой" диапазон входных данных.

2. Изменение условия требует изменения сообщения исключения. Тестовому фрэймворку все равно, а вот при отладке вручную могут возникнуть трудности, если сообщение будет неправильно описывать ситуацию.

Я мог бы привести целый ряд примеров, чтобы показать, что однострочный код работает, но вместо этого я просто запущу тест.

you@localhost: ~/diveintopython3/examples$ python3 romantest3. py -v
test_to_roman_known_values (__main__. KnownValues)
to_roman should give known result with known input... ok
test_negative (__main__. ToRomanBadInput)
to_roman should fail with negative input... ok
test_too_large (__main__. ToRomanBadInput)
to_roman should fail with large input... ok
test_zero (__main__. ToRomanBadInput)
to_roman should fail with 0 input... ok
----------------------------------------------------------------------
Ran 4 tests in 0. 016s
OK

И еще одна штука...

Еще одно требование к функциональности - обработка нецелых чисел.

> > > import roman3
> > > roman3. to_roman(0. 5) ①
''
> > > roman3. to_roman(1. 0) ②
'I'

1. О, это плохо.

2. О, а это еще хуже.

Оба случая должны выбросить исключение. Вместо этого функция возвращает ложное значение.

Тестирование не-чисел весьма сложно. Во-первых, определим исключение NotIntegerError.

# roman4. py
class OutOfRangeError(ValueError): pass
class NotIntegerError(ValueError): pass

Далее напишем тестовый случай для проверки выброса исключения NotIntegerError.

class ToRomanBadInput(unittest. TestCase):
.
.
.
def test_non_integer(self):
'''to_roman should fail with non-integer input'''
self. assertRaises(roman4. NotIntegerError, roman4. to_roman, 0. 5)

Убеждаемся, что тест провален.

you@localhost: ~/diveintopython3/examples$ python3 romantest4. py -v
test_to_roman_known_values (__main__. KnownValues)
to_roman should give known result with known input... ok
test_negative (__main__. ToRomanBadInput)
to_roman should fail with negative input... ok
test_non_integer (__main__. ToRomanBadInput)
to_roman should fail with non-integer input... FAIL
test_too_large (__main__. ToRomanBadInput)
to_roman should fail with large input... ok
test_zero (__main__. ToRomanBadInput)
to_roman should fail with 0 input... ok
======================================================================
FAIL: to_roman should fail with non-integer input
----------------------------------------------------------------------
Traceback (most recent call last):
File " romantest4. py", line 90, in test_non_integer
self. assertRaises(roman4. NotIntegerError, roman4. to_roman, 0. 5)
AssertionError: NotIntegerError not raised by to_roman
----------------------------------------------------------------------
Ran 5 tests in 0. 000s
FAILED (failures=1)

Пишем код для прохождения теста.

def to_roman(n):
'''convert integer to Roman numeral'''
if not (0 < n < 4000):
raise OutOfRangeError('number out of range (must be 1.. 3999)')
if not isinstance(n, int): ①
raise NotIntegerError('non-integers can not be converted') ②
result = ''
for numeral, integer in roman_numeral_map:
while n > = integer:
result += numeral
n -= integer
return result

1. Встроенная функция isinstance() проверяет, принадлежит ли переменная определенному типу (точнее, технически - к наследнику типа).

2. Если аргумент n не число, выбрасываем наше новое исключение NotIntegerError.

Наконец, проверим код на тесте.

you@localhost: ~/diveintopython3/examples$ python3 romantest4. py -v
test_to_roman_known_values (__main__. KnownValues)
to_roman should give known result with known input... ok
test_negative (__main__. ToRomanBadInput)
to_roman should fail with negative input... ok
test_non_integer (__main__. ToRomanBadInput)
to_roman should fail with non-integer input... ok
test_too_large (__main__. ToRomanBadInput)
to_roman should fail with large input... ok
test_zero (__main__. ToRomanBadInput)
to_roman should fail with 0 input... ok
----------------------------------------------------------------------
Ran 5 tests in 0. 000s
OK

Функция to_roman() упешно прошла все тесты, и больше тестов мне в голову не приходит, так что пора переходить к функции from_roman().

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...