Один из методов из моего кода Python не работает для некоторых юнит-тестов. Как мне улучшить его?

У меня есть этот метод с именем str_to_hex в моем файле common.py.

def str_to_hex(self, text):
    self.log.info('str_to_hex :: text=%s' % text)
    hex_string = ''
    for character in text:
        hex_string += ('%x' % ord(character)).ljust(2, '0') 
    self.log.info('str_to_hex; hex = %s' % hex_string)
    return hex_string

Метод модульного тестирования, который я пишу,

def test_str_to_hex(self):
    # test 1
    self.assertEqual(self.common.str_to_hex('test'), '74657374');
    # test 2
    self.assertEqual(self.common.str_to_hex(None) , '')
    # test 3
    self.assertEqual(self.common.str_to_hex(34234), '')
    # test 4
    self.assertEqual(self.common.str_to_hex({'k': 'v'}), '')
    # test 5  
    self.assertEqual(self.common.str_to_hex([None, 5]), '')

Итак, первые неудачи, которые я получил, говорят

# failure 1 (for test 2)
TypeError: 'NoneType' object is not iterable
# failure 2 (for test 3)
TypeError: 'int' object is not iterable
# failure 3 (for test 4)
AssertionError: '6b' != ''
# failure 4 (for test 5)
TypeError: ord() expected string of length 1, but NoneType found

В идеале в str_to_hex должен передаваться только текст (например, str или unicode).

Для обработки пустых аргументов в качестве ввода я изменил свой код с помощью

def str_to_hex(self, text):   
    # .. some code ..
    for character in text or '':
    # .. some code

Таким образом, он проходит второй тест, но все еще не проходит третий.

Если я использую hasattr(text, ' __iter__'), он все равно не пройдет тест №4 и №5.

Я думаю, что лучше всего использовать Exception. Но я открыт для предложений.

Пожалуйста, помогите мне. Заранее спасибо.


person Hussain    schedule 27.03.2015    source источник
comment
Добавляя к этому... вы тестируете дополнительные типы данных, например, dict или список, в качестве входных данных для метода? Если да, то как не отвлечь внимание от основной логики?   -  person hyades    schedule 27.03.2015
comment
Это отличный момент. Он будет работать для list при условии, что он содержит только char. например ['а', 'б', 'в']. А как насчет dict и других списков?   -  person Hussain    schedule 27.03.2015
comment
изменил вопрос   -  person Hussain    schedule 27.03.2015
comment
Почему вам нужна пустая строка, а не исключение? Похоже, это просто скроет ошибки и запутает людей, которые будут работать над этим кодом после вас.   -  person user2357112 supports Monica    schedule 27.03.2015
comment
@user2357112 user2357112 да, в идеале он должен выбрасывать разные типы Exception в разных случаях.   -  person hyades    schedule 27.03.2015
comment
Итак, какое другое исключение я должен обрабатывать, кроме TypeError и AssertionError, если метод может обрабатывать только текст?   -  person Hussain    schedule 27.03.2015


Ответы (1)


Во-первых, вам нужно решить, хотите ли вы (а) молча возвращать пустые строки для недопустимых входных данных, таких как списки, словари и т. д. ИЛИ (б) вы действительно можете создавать соответствующие исключения, просто хотите, чтобы ваши тесты справлялись с ними.

Для (а) вы можете сделать свою функцию более защищенной от того, что она получает:

def str_to_hex(self, text):
    if not isinstance(text, basestring):
        return ''
    # rest of code

Для варианта (b) вы можете изменить свои тестовые ожидания, чтобы они соответствовали тому, что происходит:

with self.assertRaises(TypeError):
    self.common.str_to_hex(None)
# etc.
person tzaman    schedule 27.03.2015
comment
Я видел, что некоторые тексты имеют тип данных = unicode (например, u'á'). Будет ли тест не пройден для такого текста? - person Hussain; 27.03.2015
comment
Я только что пробовал self.assertEqual(self.common.str_to_hex(u'á'), '') против варианта (а), и он терпит неудачу с AssertionError - person Hussain; 27.03.2015
comment
basestring позволит использовать как Unicode, так и обычные строки. ЕСЛИ вы также хотите запретить юникод, просто измените его на isinstance(text, str). - person tzaman; 27.03.2015
comment
да. это правильно. Мой тест должен был быть self.assertEqual(self.common.str_to_hex(u'á'), 'e1'). Извините :( - person Hussain; 27.03.2015
comment
Не думаю, что Вариант-А сработает. Вариант-Б на самом деле не вариант. Это не объясняет, что мы должны делать в основном коде. Здесь basestring выполняет свою работу, но во многих местах это не так. Вы закончите тем, что вставите or утверждения типа isinstance(x1) or isinstance(x2) ?? Кроме того, если вы делаете это таким образом, я думаю, что мы больше концентрируемся на тестовом коде, а не на основной логике, поскольку более половины строк кода на самом деле просто перехватывают исключения и выдают их. И это только код, который проверяет тип (бесполезная часть, которую я бы назвал), поскольку основная логика тестирования не в этом. - person hyades; 27.03.2015
comment
Я с тобой согласен. Может быть, я должен поставить проверки в декораторе. Таким образом, это будет отделено от моей фактической логики. Я тоже смешиваю фактическую логику и дополнительное покрытие. - person Hussain; 27.03.2015