Robotium+BlackBox+SlidingMenu http://t.co/v8LEA4cRMI
[Рецепт] Создание вложенных словарей для тестовых нужд без особых проблем, пример на Python
В поддержку новой инициативы Code Recipes. Искренне надеюсь на вашу помощь и всяческую поддержку в виде новых code recipes!
Если Вы программируете на Python, то знаете что словарь является очень важной структурой. И не только является важным для самого языка программирования, а и для автоматизации тестирования на этом языке. Ведь очень часто приходиться описывать данные в формате ключ: значение
. Такие данные могут быть большие по объему описываемых данных, а также не существовать в момент обращения к словарю . И если использовать стандартные механизмы словаря, то описать сложенные подсловари неудобно, а тем более если вы хотите создавать структуру данных программно в режиме runtime.
Пример, нам надо создать структуру:
{
"server": {
"host": "127.0.0.1",
"port": "22"
},
"configuration": {
"ssh": {
"access": "true",
"login": "some",
"password": "some"
}
}
}
Стандартный способ решения этой задачи
data = {}
# some logic here
print data["server"] # will raise exception due to 'KeyError: 'server''
# some logic here
data["server"] = {
"host": "127.0.0.1",
"port": "22"
}
# some logic here
if data["configuration"]["ssh"]["login"]: # will raise exception here
pass
# some logic here
data["configuration"] = {
"ssh": {
"access": "true",
"login": "some",
"password": "some"
}
}
Немного улучшенный вариант
У словаря можно использовать get метод, чтобы получить значение и не выдавать исключение и возвращать, дефолтное значение. Но если в случае с data["server"]
это сработает, то сdata["configuration"]["ssh"]["login"]
не сработает, так как возвращаемый объект будет типа None
data = {}
# some logic here
print data.get("server")
# some logic here
data["server"] = {
"host": "127.0.0.1",
"port": "22"
}
# some logic here
if data.get("configuration").get("ssh").get("login"):
# will raise exception
# AttributeError: 'NoneType' object has no attribute 'get'
pass
# some logic here
data["configuration"] = {
"ssh": {
"access": "true",
"login": "some",
"password": "some"
}
}
Но если задать дефолтные значения дляdata.get("configuration").get("ssh").get("login")
чтобы не получать ошибкуAttributeError: 'NoneType' object has no attribute 'get'
, то можно получить нормальный результат
data = {}
# some logic here
print data.get("server")
# some logic here
data["server"] = {
"host": "127.0.0.1",
"port": "22"
}
# some logic here
if data.get("configuration", {}).get("ssh", {}).get("login", {}):
# will raise exception
# AttributeError: 'NoneType' object has no attribute 'get'
pass
# some logic here
data["configuration"] = {
"ssh": {
"access": "true",
"login": "some",
"password": "some"
}
}
Готовый рецепт, усовершенствованный способ
А можно использовать возможности defaultdict
from collections import defaultdict _default_data = lambda: defaultdict(_default_data) data = _default_data() # some logic here print data["server"] # some logic here data["server"]["host"] = "127.0.0.1" data["server"]["port"] = "22" # some logic here if data["configuration"]["ssh"]["login"]: print ("some logic") # some logic here data["configuration"]["ssh"]["access"] = "true" data["configuration"]["ssh"]["login"] = "some" data["configuration"]["ssh"]["password"] = "some" import json print json.dumps(data, indent=2)
defaultdict(<function <lambda> at 0x02565930>, {}) { "configuration": { "ssh": { "access": "true", "login": "some", "password": "some" } }, "server": { "host": "127.0.0.1", "port": "22" } }
Результат получается без всяких исключений и сложностей, и мы можем задавать любую структуру из подвложенных словарей без фактического определения самих объектов, а также получаем возможность проверки словаря без исключений и удобную стандартную форму записи словаря.
Все варианты кода можно посмотреть на нашей общем репозитории примеровhttps://github.com/atinfo/at.info-knowledge-base/tree/master/programming/python/code%20recipes/generate%20nested%20dicts
Ну и кто хочет учиться python и автоматизации, милости прошу на http://lessons2.ru
Разделение stdout и stderr в python nosetest
Проблема: в python есть популярный xUnit фреймворк nose, которым пользуются довольно много людей. Когда подключаешь nose к continuous integration, то хочешь чтобы результаты были максимально видимыми и репрезентативными. Но вот есть одна проблема, всю выходную информацию nose записывает в один поток, либо stdout либо stderr. А как же быть, если нам нужно показать часть в stderr, а часть в stdout?
Например
Результат прогона полностью выводиться в stderr:
#1 Test 1 … ok
#2 Test 2 … FAIL
#3 Test 3 … ok
#4 Test 4 … ok
#5 Test 5 … FAIL
==============================
FAIL: Test 2
——————————
Traceback (most recent call last):
File “/home/katerina/Desktop/my_
self.assertEquals(1, 2)
AssertionError: 1 != 2
==============================
FAIL: Test 5
——————————
Traceback (most recent call last):
File “/home/katerina/Desktop/my_
self.assertEquals(1, 7)
AssertionError: 1 != 7
——————————
XML: nosetests.xml
——————————
Ran 5 tests in 0.004s
FAILED (failures=2)
А надо чтоб результат выводился в 2 потока:
#1 Test 1 … ok
#2 Test 2 … FAIL
#3 Test 3 … ok
#4 Test 4 … ok
#5 Test 5 … FAIL
==============================
FAIL: Test 2
——————————
Traceback (most recent call last):
File “/home/katerina/Desktop/my_
self.assertEquals(1, 2)
AssertionError: 1 != 2
==============================
FAIL: Test 5
——————————
Traceback (most recent call last):
File “/home/katerina/Desktop/my_
self.assertEquals(1, 7)
AssertionError: 1 != 7
——————————
XML: nosetests.xml
——————————
Ran 5 tests in 0.004s
FAILED (failures=2)
Вся соль в том, что nose основывает весь свой запуск на unittest. А в unittest используется механизм буферизации stdout и stderr, т.е. unittest все ловит, но в последствии все уходит в один поток. Этот поток по умолчанию stderr. Его конечно можно поменять, но все равно это запись содержимого прогона в один поток или stderr или stdout.
Решение: простое решение – это переопределить TextTestResult и TextTestRunner при запуске тестов. Смотрим пример:
import unittest import sys import nose from nose.core import TextTestRunner from nose.result import TextTestResult from cStringIO import StringIO class Tests(unittest.TestCase): def test_1(self): """Test 1""" print 'something' self.assertEquals(1, 1) def test_2(self): """Test 2""" self.assertEquals(1, 1) def test_3(self): """Test 3""" self.assertEquals(1, 1) def test_4(self): """Test 4""" self.assertEquals(1, 1) def test_5(self): """Test 5""" print 'something' raise AssertionError("error") self.assertEquals(1, 1) if __name__ == '__main__': class MyTextTestResult(TextTestResult): def addError(self, test, err): print >> sys.stderr, "%r ... error\n\t%r" % (test, err) def addFailure(self, test, err): print >> sys.stderr, "%r ... failure\n\t%r" % (test, err) def addSuccess(self, test): print >> sys.stdout, "%r ... ok" % test class MyTextTestRunner(TextTestRunner): def __init__(self): TextTestRunner.__init__(self, stream=StringIO()) def _makeResult(self): return MyTextTestResult(self.stream, self.descriptions, self.verbosity, self.config) nose.main(testRunner=MyTextTestRunner())
Пример можно скачать здесь https://github.com/polusok/nose-split-stderr-stdout. Это далеко не идеальное решение, но позволит Вам быстро решить вашу задачу.
Успехов и хорошего питонирования!
З.Ы. С 05.08 стартует следующая группа по обучению программированию на python для начинающих. Еще можно записаться!
Логирование и декораторы в python
Вопрос логирования очень часто возникает при автоматизации тестирования. Каждый кто автоматизировал больше одного теста знает, что логи это ключ к сэкономленным часам анализа ошибок и разборов поломанных тестов.
Как правильно выполнить логирование для Вашего проекта? Не знаю, каждый проект это отдельная история, которая должна рассматриваться в отдельности. (Обращайтесь, будем разбираться!) Но я хочу внести некоторые свои комментарии в данный процесс.
Меня попросили посмотреть на код и показать, как можно выводить документацию для каждого метода в лог. В python это лучше всего сделать с помощью декораторов. Декораторы – это мощная штука! В общем, меньше слов и больше кода.
import logging def method_decorator(func): def wrapper(self, *argv, **kwargv): logging.basicConfig(filename='myapp.log', level=logging.INFO) logging.info(func.__doc__) return func(self, *argv, **kwargv) return wrapper class Something1(object): @method_decorator def method1(self): """documentation thru method decorator for method 1""" pass def method2(self): """documentation thru method decorator for method 2""" pass @method_decorator def method3(self): """documentation thru method decorator for method 3""" pass s1 = Something1() s1.method1() s1.method2() s1.method3() # or thru class decorator def class_decorator(cls): for name, method in cls.__dict__.iteritems(): if not name.startswith('_'): setattr(cls, name, method_decorator(method)) return cls @class_decorator class Something2(object): def method1(self): """documentation thru class decorator for method 1""" pass def method2(self): """documentation thru class decorator for method 2""" pass def method3(self): """documentation thru class decorator for method 3""" pass s2 = Something2() s2.method1() s2.method2() s2.method3() #check mixed execution s1.method1() s2.method1()
Т.е. мы описываем необходимый читабельный комментарий как docstring для методов, и когда эти методы вызываются, в лог записывается читабельная информация. В первом случае, можно использовать декоратор для методов, который можно использовать по требованию. А второй класс показывает, как можно включить данное логирование для всех методов класса. Или же Вы можете задать любую необходимую вам логику в class_decorator().
Вот, что мы получаем в логе:
INFO:root:documentation thru method decorator for method 1 INFO:root:documentation thru method decorator for method 3 INFO:root:documentation thru class decorator for method 1 INFO:root:documentation thru class decorator for method 2 INFO:root:documentation thru class decorator for method 3 INFO:root:documentation thru method decorator for method 1 INFO:root:documentation thru class decorator for method 1
Ну а теперь давайте подключим это к каким-то юнит-тестам. Например, это может выглядеть так.
import logging import unittest import random from functools import wraps def method_decorator(func): @wraps(func) def wrapper(self, *argv, **kwargv): logging.basicConfig(filename='myapp.log', level=logging.INFO, format='%(message)s') logging.info("\t- %s" % func.__doc__) return func(self, *argv, **kwargv) return wrapper def class_decorator(cls): for name, method in cls.__dict__.iteritems(): if not name.startswith('_'): setattr(cls, name, method_decorator(method)) return cls class MyTestingException(Exception): def __init__(self, value): self.msg = value def __str__(self): return "%s\n%s" % (self.msg, open("myapp.log").read()) @class_decorator class Something(object): def _generate_number(self): if random.randint(0, 10) == 5: raise MyTestingException("Please have a look to details:") return random.randint(0, 2) def method1(self): """log to system to make some actions""" return self._generate_number() def method2(self): """registered account with additional credits""" return self._generate_number() def method3(self): """buy subscription for defined account""" return self._generate_number() class TestSomething(unittest.TestCase): def setUp(self): with open("myapp.log", "w") as f: f.truncate() self.s = Something() self.data = {'some data': [1, 2, 3]} def test_method1(self): self.s.method1() self.s.method2() self.s.method3() self.assertEquals(self.s.method1(), 0) def test_method2(self): self.s.method3() self.s.method2() self.s.method1() self.assertEquals(self.s.method2(), 1) def test_method3(self): self.s.method1() self.s.method3() self.s.method2() self.assertEquals(self.s.method3(), 2) if __name__ == '__main__': unittest.main()
Что дает следующие результаты:
EFE ====================================================================== ERROR: test_method1 (__main__.TestSomething) ---------------------------------------------------------------------- Traceback (most recent call last): File "demo.py", line 64, in test_method1 self.s.method3() File "demo.py", line 12, in wrapper return func(self, *argv, **kwargv) File "demo.py", line 50, in method3 return self._generate_number() File "demo.py", line 37, in _generate_number raise MyTestingException("Please have a look to details:") MyTestingException: Please have a look to details: - log to system to make some actions - registered account with additional credits - buy subscription for defined account ====================================================================== ERROR: test_method3 (__main__.TestSomething) ---------------------------------------------------------------------- Traceback (most recent call last): File "demo.py", line 77, in test_method3 self.assertEquals(self.s.method3(), 2) File "demo.py", line 12, in wrapper return func(self, *argv, **kwargv) File "demo.py", line 50, in method3 return self._generate_number() File "demo.py", line 37, in _generate_number raise MyTestingException("Please have a look to details:") MyTestingException: Please have a look to details: - log to system to make some actions - buy subscription for defined account - registered account with additional credits - buy subscription for defined account ====================================================================== FAIL: test_method2 (__main__.TestSomething) ---------------------------------------------------------------------- Traceback (most recent call last): File "demo.py", line 71, in test_method2 self.assertEquals(self.s.method2(), 1) AssertionError: 2 != 1 ---------------------------------------------------------------------- Ran 3 tests in 0.003s FAILED (failures=1, errors=2)
Как всегда, пишите, если у Вас есть вопросы! Удачи и хорошего Вам питонирования!
Жизненные советы от Алекса Дубаса
Жизнь приносит нам слезы и радость, смех и разочарование. Люди, отношения, семья, здоровье, родители, зависть … Это лишь небольшая часть того, о чем мы думаем или, к сожалению, не думаем каждый день. А стоило бы. Ведь это и есть жизнь!
Да кстати о жизни, посмотрите видео. Не пожалеете!
А для тех, кто знает английский могут посмотреть английскую версию (оригинал) (как всегда, в СНГ сами сделать ничего не могут )
Как сдать ISTQB сертификацию в Украине?
Так как я являюсь обладателем аж 3х сертификаций данной организации, мне часто задают одни и те же вопросы. Вот недавно снова пришел подобный емейл. Значит надо оформить статью и потом высылать ее всем . Как я буду писать ее, да просто в формате вопросов, которые мне задают и моих ответов. Если Вы хотите спросить еще какие-то вопросы, you are welcome! Буду добавлять информацию по мере надобности.
- Как проходит подготовка к Foundation Level экзамену?
выдаются задания и есть определенное время
вы решаете и cдаете и все - Вам было достаточно почитать примеры и доп. литературу?
для меня да
для других не сильно
есть много ресурсов, где можно найти примерочные тесты - Основывается ли экзамен на общепризнанных прадигмах тестирования?
интересный вопрос, но для меня не понятный, что Вы имеете ввиду
- Какие основные “подводные камни” Вы заметили в экзамене?
много разных вариантов определения какого-то термина
ну и надо знать все подходы, я бы сказал так
если вы прочитали книгу, вы сможете без проблем сдать экзамен - Какова стоимость сдачи экзамена в Украине?
125 евро - Как проходит регистрация, и к кому обращаться? (Александр Тарасенко редко реагирует на письма/звонки)
именно к Тарасенко и нужно
но в общем, начальный уровень можно сдать в любом prometric центре
так что можно не заморачиваться на счет тарасенка
https://www.isqi.org/en/e-exams.html - В каком виде выдаётся сертификат?
в бумажном, приходят на почту - И по литературе – какие книги Вы бы посоветовали?
FOUNDATIONS OF SOFTWARE TESTING, ISTQB CERTIFICATION, Dorothy Graham, Erik van Veenendaal, Isabel Evans, Rex Black (2 книги 2008 и 2012 годов)
Advanced Software Testing, Rex Black (3 книги) - Какого рода вопросы для foundation level?
Вопросы, которые подразумевают выбор одного или несколько вариантов правильных ответов из перечисленных вариантов. - Я прочитала на Вашем сайте, что вы сдали ISTQB Advanced Test Analyst экзамен.
Какими материалами Вы пользовались при подготовке кроме силлабуса и стандартной книги?
Остались ли у Вас ссылки, если да, то поделитесь, пожалуйста.
Я пользовался стандартными книгами Advanced Testing Vol1 и Advanced Testing Vol2 и Advanced Testing Vol3 автор Rex Black.
К сожалению, одного силлабуса не хватит для того, чтобы подготовиться к advance уровню. - ISTQB Advanced Test Analyst экзамен. Я знаю, что в экзаменационном тесте возможны несколько вариантов правильных ответов. Есть ли в вопросе точное указание на их количество или они перечислены в одном пункте?
Да некоторые вопросы могут содержать 1 или более правильных ответов, но об этом нигде не написано и не обозначено. Т.е. это будет вопросы с несколькими ответами и Вам надо будет отметить один или более правильных ответов. Но все таки в некоторых вопросах есть упоминание: “вычеркните все которые … ” или “укажите все правильные варианты …”. В общем, надо просто быть внимательным к мелочам и деталям, а также пользоваться здравой логикой. - ISTQB Advanced Test Analyst экзамен. Я тоже недавно сдавала этот экзамен, но не сдала. Буду пересдавать. При подготовке я пользовалась силлабусом и стандартной книгой. Но в тесте я встречала термины, о которых ничего не сказано в книге. Так что я думаю, что нужны другие материалы для подготовки.
Да силлабус и книги не гарантируют, что Вы будете знать все термины. Я вам так скажу, если Вы прочитаете все три книги, которые я указал, то сдавать будет проще, потому что одна книга дополняют другую. Плюс надо учитывать, что экзамены обновляются постоянно, а книги выпущены все один раз и там некоторая информация уже может быть устаревшей или же в авторы экзамена могли поменять смысл чего-либо. Потому тут так, читайте все литературу и проходите как можно больше заданий. Интернет вам поможет. Есть также круг людей, которые собираются и решают задачи вместе, а есть даже люди, которые учат, как сдать на этот сертификат. - ISTQB Advanced Test Analyst экзамен. И последний вопрос, знаете ли вы как начисляются баллы. Если в вопросе два ответа, а я выбрала только один, то сколько баллов будет за такой ответ?
Я точной схемы начисления баллов не помню. Это нужно уточнять на месте. Если кто-то знает, буду рад добавить текст сюда.
Updated: Я еще раз переспросила на счет кол-ва правильных ответов в rstqb. Вот что мне ответили “По умолчанию верный только один ответ, если не сказано иного. За верный ответ на вопросы уровня K2 начисляется 1 балл, на вопросы уровней K3 и K4 – по 2 балла”
В общем, если у кого-то возникают похожие вопросы, пишите комментарий буду отвечать и набивать соответствующий FAQ
Что еще можно почитать?
http://automated-testing.info/forum/….istqb-ctfl-ctal
http://automated-testing.info/forum/…-istqb
Mykhailo Poliarush
| #
Добрый день, это вывод вы сделали по каким урокам?
Valerii Synenko
| #
Опис курсу шикарний, теми затронуті правильні, але ведення курсу: “це сюди, те туди, все ж ясно!”, пояснень = 0.
Igor Vlasuyk
| #
“Продолжительность 16 часов (2 дня)”
Это то есть 2 рабочих дня надо полностью быть на тренинге?
И на каком языке программирования будет практика?
Nataliia Koval
| #
Большое спасибо! С расписанием вроде разобралась.
Chmel Viktor
| #
Доброго дня