{
"metadata": {
"name": "Capitulo25_Testes_automatizados"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[Python para Desenvolvedores](http://ricardoduarte.github.io/python-para-desenvolvedores/#conteudo)\n",
"===================================\n",
"2ª edi\u00e7\u00e3o, revisada e ampliada\n",
"-----------------------------------\n",
"\n",
"Cap\u00edtulo 25: Testes automatizados\n",
"=============================\n",
"_____________________________\n",
"A atividade de testar software \u00e9 uma tarefa repetitiva, demorada e tediosa. Por isso, surgiram v\u00e1rias ferramentas para automatizar testes. Existem dois m\u00f3dulos para testes automatizados que acompanham o Python: *doctest* e *unittest*.\n",
"\n",
"O m\u00f3dulo *doctest* usa as *Doc Strings* que est\u00e3o presentes no c\u00f3digo para definir os testes do c\u00f3digo. A fun\u00e7\u00e3o `testmod()` do *doctest* procura por um trecho de texto seja semelhante a uma sess\u00e3o interativa de Python, executa a mesma sequ\u00eancia de comandos, analisa a sa\u00edda e faz um relat\u00f3rio dos testes que falharam, com os erros encontrados."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"\"\"\n",
"Implementa Fibonacci.\n",
"\"\"\"\n",
"\n",
"def fib(n):\n",
" \"\"\"Fibonacci:\n",
" Se n <= 1, fib(n) = 1\n",
" Se n > 1, fib(n) = fib(n - 1) + fib(n - 2)\n",
" \n",
" Exemplos de uso:\n",
" \n",
" >>> fib(0)\n",
" 1\n",
" >>> fib(1)\n",
" 1\n",
" >>> fib(10)\n",
" 100\n",
" >>> [ fib(x) for x in xrange(10) ]\n",
" [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]\n",
" >>> fib('')\n",
" Traceback (most recent call last):\n",
" File \"\", line 1, in ?\n",
" File \"\", line 19, in fib\n",
" TypeError\n",
" >>> \n",
" \"\"\"\n",
" if not type(n) is int:\n",
" raise TypeError\n",
"\n",
" if n > 1:\n",
" return fib(n - 1) + fib(n - 2)\n",
" else:\n",
" return 1\n",
"\n",
"def _doctest():\n",
" \"\"\"\n",
" Evoca o doctest.\n",
" \"\"\"\n",
"\n",
" import doctest\n",
" doctest.run_docstring_examples(fib, globals())\n",
"\n",
"if __name__ == \"__main__\":\n",
"\n",
" _doctest()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"**********************************************************************\n",
"File \"__main__\", line 16, in NoName\n",
"Failed example:\n",
" fib(10)\n",
"Expected:\n",
" 100\n",
"Got:\n",
" 89\n"
]
}
],
"prompt_number": 6
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Se todos os testes forem bem sucedidos, n\u00e3o haver\u00e1 relat\u00f3rio dos testes.\n",
"\n",
"A sa\u00edda do c\u00f3digo acima \u00e9 um exemplo de relat\u00f3rio de erros dos testes (a Doc String foi alterada de prop\u00f3sito para gerar um erro).\n",
"\n",
"Usando o m\u00f3dulo *unittest*, os testes s\u00e3o criados atrav\u00e9s de uma subclasse da classe unittest.TestCase. Os testes s\u00e3o definidos como m\u00e9todos da subclasse. Os m\u00e9todos precisam ter seus nomes iniciando com `test` para que sejam identificados como rotinas de teste.\n",
"\n",
"Os m\u00e9todos de teste devem evocar ao terminar um dos m\u00e9todos:\n",
"\n",
"+ *assert_*: verifica se uma condi\u00e7\u00e3o \u00e9 atingida.\n",
"+ *assertEqual*: verifica se o resultado \u00e9 igual ao par\u00e2metro passado.\n",
"+ *AssertRaises*: verifica se a exce\u00e7\u00e3o \u00e9 a esperada.\n",
"\n",
"Se houver um m\u00e9todo chamado *setUp*, este ser\u00e1 executado antes de cada teste, assim \u00e9 poss\u00edvel reinicializar vari\u00e1veis e garantir que um teste n\u00e3o prejudique o outro. O final dos testes, o *unittest* gera o relat\u00f3rio com os resultados encontrados.\n",
"\n",
"Exemplo:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"\"\"\n",
"\n",
"Usa unittest para testar fib.py.\n",
"\"\"\"\n",
"\n",
"import fib\n",
"import unittest\n",
"\n",
"class TestSequenceFunctions(unittest.TestCase):\n",
"\n",
" def setUp(self):\n",
" self.seq = range(10)\n",
"\n",
" def test0(self):\n",
" self.assertEqual(fib.fib(0), 1)\n",
"\n",
" def test1(self):\n",
" self.assertEqual(fib.fib(1), 1)\n",
"\n",
" def test10(self):\n",
" self.assertEqual(fib.fib(10), 89)\n",
"\n",
" def testseq(self):\n",
" fibs = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]\n",
" \n",
" for x, y in zip(fibs, [ fib.fib(x) for x in self.seq ]):\n",
" self.assert_(x is y)\n",
"\n",
" def testtype(self):\n",
" self.assertRaises(TypeError, fib.fib, '')\n",
"\n",
"if __name__ == '__main__':\n",
" \n",
" suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)\n",
" unittest.TextTestRunner(verbosity=2).run(suite)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 12
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Exemplo de relat\u00f3rio com erros:\n",
"\n",
" ..F..\n",
" ======================================================================\n",
" FAIL: test10 (__main__.TestSequenceFunctions)\n",
" ----------------------------------------------------------------------\n",
" Traceback (most recent call last):\n",
" File \"unittest1.py\", line 22, in test10\n",
" self.assertEqual(fib.fib(10), 89)\n",
" AssertionError: 100 != 89\n",
" \n",
" ----------------------------------------------------------------------\n",
" Ran 5 tests in 0.000s\n",
" \n",
" FAILED (failures=1)\n",
"\n",
"No relat\u00f3rio, o terceiro teste falhou, pois `fib.fib(10)` retornou 100 ao inv\u00e9s de 89, como seria o esperado.\n",
"\n",
"O *unittest* oferece uma solu\u00e7\u00e3o muito semelhante a bibliotecas de testes implementadas em outras linguagens, enquanto o *doctest* \u00e9 mais simples de usar e se integra bem com a documenta\u00e7\u00e3o (as sess\u00f5es do doctest podem servir como exemplos de uso)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"\n",
""
],
"output_type": "pyout",
"prompt_number": 1,
"text": [
""
]
}
],
"prompt_number": 1
}
],
"metadata": {}
}
]
}