Python for testers

Posts Tagged ‘ИТ’

Разделение stdout и stderr в python nosetest

Written by Михаил Поляруш on . Posted in Автоматизация, Работаю, Разработка

Проблема: в 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_tests/color.py”, line 11, in test_2
    self.assertEquals(1, 2)
AssertionError: 1 != 2

======================================================================
FAIL: Test 5
———————————————————————-
Traceback (most recent call last):
  File “/home/katerina/Desktop/my_tests/color.py”, line 23, in test_5
    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_tests/color.py”, line 11, in test_2
    self.assertEquals(1, 2)
AssertionError: 1 != 2

======================================================================
FAIL: Test 5
———————————————————————-
Traceback (most recent call last):
  File “/home/katerina/Desktop/my_tests/color.py”, line 23, in test_5
    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

Written by Михаил Поляруш on . Posted in Автоматизация, Разработка

Вопрос логирования очень часто возникает при автоматизации тестирования. Каждый кто автоматизировал больше одного теста знает, что логи это ключ к сэкономленным часам анализа ошибок и разборов поломанных тестов.

Как правильно выполнить логирование для Вашего проекта? Не знаю, каждый проект это отдельная история, которая должна рассматриваться в отдельности. (Обращайтесь, будем разбираться!) Но я хочу внести некоторые свои комментарии в данный процесс.

Меня попросили посмотреть на код и показать, как можно выводить документацию для каждого метода в лог. В 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 сертификацию в Украине?

Written by Михаил Поляруш on . Posted in Tестирование

Так как я являюсь обладателем аж 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

Выступил на конференции atdays 2013

Written by Михаил Поляруш on . Posted in Автоматизация, Работаю, Тренинги

На этих выходных (09.02.2013) я проводил и выступал на конференции Test Automation Days. За конференцию еще буду писать отдельно, а вот просто хочу поделиться слайдами моего доклада, как быстро расширять robot framework под свои потребности на python.

Тренинг основы автоматизации – отчет по следующей группе

Written by Михаил Поляруш on . Posted in Автоматизация, Тренинги

Провел очередной тренинг по основам автоматизации тестирования ПО. Собралась группа 13 человек из разных проектов и с разными навыками. Должен констатировать факт, что все-таки осведомленность специалистов начального и среднего уровня об автоматизации тестирования остается на низком уровне. А ведь в Украине выполняется множество  проектов по автоматизации.

Меня посетила мысль, почему так происходит. Автоматизация – это промежуточное звено перед чем-то большим. Очень мало людей остается именно в этой роли. Поэтому специалист по автоматизации тестирования существует в среднем 2-3 года, а потом движется дальше. Соответственно,  этим и объясняется количество людей, занятых в автоматизации. Хотя по истории проведения своих авторских тренингов должен сказать, что все больше людей интересуется автоматизацией. Потому что методы разработки ПО заставляют команды использовать автоматизацию, хотят они этого или нет. Без этого просто быстро нельзя поставить ПО заказчику. При этом получается определенная пропасть в знаниях между специалистами, которые знают автоматизацию и теми, кто ее не знает.

В общем, это лирика :) Тренинг прошел успешно. По балам приблизительно 4.6 из 5. Есть несколько моментов в тренинге, которые я переделаю, а также решил еще добавить немного live coding и живых демонстраций, чтобы тренинг стал более полезным и интересным. Фотографии прикладываю.


Скоро у меня стартует марафон тренингов. Группы полностью укомплектованы. Буду учить подрастающее поколение.

Twitter лента

autotestinfo

Как продолжить тест при случайном появлении попапа? http://t.co/tGqX8PjPzD

mpoliarush

http://t.co/9879JVgl21 automates tests written with QUnit, Jasmine, Mocha with Expect.js assertions, Dojo Objective Harness, or YUI Test.