# 5.1 Isolamento dos Testes Funcionais

Ao encerrarmos o capítulo anterior, nossa aplicação apresentava um pequeno problema que era o acúmulo de itens na lista em execuções sucessivas dos casos de teste. Outro inconveniente que temos em nosso código de testes são os `time.sleeps`. Durante este capítulo iremos deixar um pouco de lado no desenvolvimento do código da aplicação para nos concentrarmos na melhoria do nosso conjunto de teste funcional.

Nesta seção abordaremos o isolamento dos testes e como eliminar as repetições de inclusão de itens na lista durante execuções sucessivas dos testes. Na Seção 5.2 vamos tratar da questão de sincronização.

O framework `unittest` oferece métodos que nos permitem executar ações antes ou após cada caso de teste, são os métodos `setUp` e `tearDown`, respectivamente. Poderíamos utilizá-los para fazer, antes de cada teste, colocar o sistema em um estado conhecido válido e, posteriormente, limpar os dados produzidos durante a execução de um teste. Entretanto, o Django oferece uma classe de teste, denominada `LiveServerTestCase` que nos proporciona recursos semelhantes aqueles utilizados nos testes unitários, ou seja, do isolamento dos testes em execuções sucessivas. Essa classe é responsável por criar, automaticamente, um banco de dados de teste.

Testes derivados de `LiveServerTestCase`  esperam ser executados pelo executor de testes do Django e, para isso precisamos reorganizar os arquivos contendo os testes para indicar ao Djando qual conjunto de teste desejamos executar em dado momento. Desse modo, vamos criar uma pasta para acomodar nossos testes funcionais um nível abaixo de nosso diretório de trabalho. Tudo que o Django necessita é uma pasta com um arquivo **`__init__.py`**&#x64;entro dela.

```bash
(superlists) tdd@mlp:~/superlists/superlists$ mkdir functional_tests
(superlists) tdd@mlp:~/superlists/superlists$ touch functional_tests/__init__.py
```

Em seguida, como nosso código está sob controle de versão, podemos utilizar os comandos do Git para movimentação de arquivos conforme abaixo:

```bash
(superlists) tdd@mlp:~/superlists/superlists$ git mv functional_tests.py functional_tests/tests.py

(superlists) tdd@mlp:~/superlists/superlists$ git status
No ramo master
Your branch is up to date with 'origin/master'.

Mudanças a serem submetidas:
  (use "git restore --staged <file>..." to unstage)
	renamed:    functional_tests.py -> functional_tests/tests.py

Arquivos não monitorados:
  (utilize "git add <arquivo>..." para incluir o que será submetido)
	functional_tests/__init__.py
```

Com essa alteração, `functional_tests.py` passou a ser `functional_tests/tests.py`. O conteúdo do novo arquivo também precisa ser alterado para fazer uso da classe `LiveServerTestCase`, conforme abaixo.

{% code lineNumbers="true" %}

```python
from django.test import LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By

import time

class NewVisitorTest(LiveServerTestCase):

	def setUp(self):
		self.browser = webdriver.Firefox()

	def tearDown(self):
		self.browser.quit()

	# Auxiliary method 
	def check_for_row_in_list_table(self, row_text):
		table = self.browser.find_element(By.ID,'id_list_table')
		rows = table.find_elements(By.TAG_NAME, 'tr')
		self.assertIn(row_text, [row.text for row in rows])

	def test_can_start_a_list_and_retrieve_it_later(self):
		# Edith ouviu falar de uma nova aplicação online interessante
		# para lista de tarefas. Ela decide verificar a homepage

		self.browser.get(self.live_server_url)

		# Ela percebe que o título da página e o cabeçalho mencionam
		# listas de tarefas (to-do)

		self.assertIn('To-Do', self.browser.title)
		header_text = self.browser.find_element(By.TAG_NAME, 'h1').text
		self.assertIn('To-Do', header_text)
		
		# Ela é convidada a inserir um item de tarefa imediatamente

		inputbox = self.browser.find_element(By.ID, 'id_new_item')
		self.assertEqual(
			inputbox.get_attribute('placeholder'),
			'Enter a to-do item'
		)

		# Ela digita "Buy peacock feathers" (Comprar penas de pavão)
		# em uma nova caixa de texto (o hobby de Edith é fazer iscas
		# para pesca com fly)

		inputbox.send_keys('Buy peacock feathers')


		# Quando ela tecla enter, a página é atualizada, e agora
		# a página lista "1 - Buy peacock feathers" como um item em 
		# uma lista de tarefas

		inputbox.send_keys(Keys.ENTER)
		time.sleep(1)
		self.check_for_row_in_list_table('1: Buy peacock feathers')

		# Ainda continua havendo uma caixa de texto convidando-a a 
		# acrescentar outro item. Ela insere "Use peacock feathers 
		# make a fly" (Usar penas de pavão para fazer um fly - 
		# Edith é bem metódica)
		inputbox = self.browser.find_element(By.ID,'id_new_item')
		inputbox.send_keys("Use peacock feathers to make a fly")
		inputbox.send_keys(Keys.ENTER)
		time.sleep(1)

		# A página é atualizada novamente e agora mostra os dois
		# itens em sua lista
		self.check_for_row_in_list_table('1: Buy peacock feathers')
		self.check_for_row_in_list_table('2: Use peacock feathers to make a fly')

		# Edith se pergunta se o site lembrará de sua lista. Então
		# ela nota que o site gerou um URL único para ela -- há um 
		# pequeno texto explicativo para isso.

		self.fail('Finish the test!')

		# Ela acessa essa URL -- sua lista de tarefas continua lá.

		# Satisfeita, ela volta a dormir
```

{% endcode %}

Basicamente, incluímos a dependência de `LiveServerTestCase` (linha 1), modificamos a URL utilizada na linha 26 de `self.browser.get(http://localhost:8000/)` para `self.browser.get(self.live_server_url)`, que identifica corretamente a URL e a porta relacionada com o servidor de teste. Além disso, as linhas de código abaixo podem ser removidas do servidor de teste, pois a execução dos mesmos se dará via `manage.py`.

```python
if __name__ == '__main__':
	unittest.main()
```

Com essas alterações, a execução dos testes funcionais passa a ser realizadas agora da seguinte forma:

{% code lineNumbers="true" %}

```bash
(superlists) tdd@mlp:~/superlists/superlists$ python manage.py test functional_tests
Found 1 test(s).
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (functional_tests.tests.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tdd/superlists/superlists/functional_tests/tests.py", line 76, in test_can_start_a_list_and_retrieve_it_later
    self.fail('Finish the test!')
AssertionError: Finish the test!

----------------------------------------------------------------------
Ran 1 test in 6.021s

FAILED (failures=1)
```

{% endcode %}

Observe que agora, ao executa os testes, o Django cria uma base auxiliar apenas para a execução dos testes, que é destruída no encerramento dos testes, conforme mensagens nas linhas 2 e 16, respectivamente.

Antes de continuarmos, vamos colocar nosso código e suas alterações no controle de verão:

```bash
(superlists) tdd@mlp:~/superlists/superlists$ git status 
No ramo master
Your branch is up to date with 'origin/master'.

Mudanças a serem submetidas:
  (use "git restore --staged <file>..." to unstage)
	renamed:    functional_tests.py -> functional_tests/tests.py

Changes not staged for commit:
  (utilize "git add <arquivo>..." para atualizar o que será submetido)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   functional_tests/tests.py

Arquivos não monitorados:
  (utilize "git add <arquivo>..." para incluir o que será submetido)
	functional_tests/__init__.py

(superlists) tdd@mlp:~/superlists/superlists$ git add functional_tests

(superlists) tdd@mlp:~/superlists/superlists$ git commit -am "Make functional_tests an app using LiveServerTestCase."
[master 04657aa] Make functional_tests an app using LiveServerTestCase.
 2 files changed, 4 insertions(+), 7 deletions(-)
 create mode 100644 functional_tests/__init__.py
 rename functional_tests.py => functional_tests/tests.py (93%)
 
(superlists) tdd@mlp:~/superlists/superlists$ git push
Username for 'https://github.com': aurimrv
Password for 'https://aurimrv@github.com': 
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 1.44 KiB | 1.44 MiB/s, done.
Total 4 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/aurimrv/superlists.git
   06e3205..04657aa  master -> master
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://aurimrv.gitbook.io/tdd-python/5-melhorando-e-organizando-os-conjuntos-de-teste/5-1-isolamento-do-testes-funcionais.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
