6.6 Alterando Modelos
Vamos caminhar agora para a solução do nosso problema mais complicado que é o de lidar com diferentes URLs para usuários distintos.
Iniciamos alterando nossos testes unitários para lidar com o que precisamos. O novo conjunto de teste unitário ficou conforme abaixo. Incluí um # ao final de cada linha que foi incluída.
from django.urls import resolve
from django.test import TestCase
from lists.views import home_page
from lists.models import Item, List #
class HomePageTest(TestCase):
def test_root_url_resolves_to_home_page_view(self):
found = resolve('/')
self.assertEquals(found.func, home_page)
def test_home_page_returns_correct_html(self):
response = self.client.get('/')
self.assertTemplateUsed(response, 'home.html')
def test_only_saves_items_when_necessary(self):
self.client.get('/')
self.assertEquals(Item.objects.count(), 0)
class NewListTest(TestCase):
def test_can_save_a_POST_request(self):
self.client.post('/lists/new', data={'item_text': 'A new list item'})
self.assertEquals(Item.objects.count(), 1)
new_item = Item.objects.first()
self.assertEquals(new_item.text, 'A new list item')
def test_redirects_after_POST(self):
response = self.client.post('/lists/new', data={'item_text': 'A new list item'})
self.assertRedirects(response, '/lists/the-only-list-in-the-world/')
class ListViewTest(TestCase):
def test_uses_list_template(self):
response = self.client.get('/lists/the-only-list-in-the-world/')
self.assertTemplateUsed(response, 'list.html')
def test_displays_all_list_itens(self):
Item.objects.create(text='itemey 1')
Item.objects.create(text='itemey 2')
response = self.client.get('/lists/the-only-list-in-the-world/')
self.assertContains(response, 'itemey 1')
self.assertContains(response, 'itemey 2')
class ListAndItemModelTest(TestCase): #
def test_saving_and_retriving_items(self):
list_ = List() #
list_.save() #
first_item = Item()
first_item.text = 'The first (ever) list item'
first_item.list = list_ #
first_item.save()
second_item = Item()
second_item.text = 'Item the second'
second_item.list = list_
second_item.save()
saved_list = List.objects.first() #
self.assertEquals(saved_list, list_) #
saved_items = Item.objects.all()
self.assertEquals(saved_items.count(),2)
first_saved_item = saved_items[0]
second_saved_item = saved_items[1]
self.assertEquals(first_saved_item.text, 'The first (ever) list item')
self.assertEquals(first_saved_item.list, list_) #
self.assertEquals(second_saved_item.text, 'Item the second')
self.assertEquals(second_saved_item.list, list_) #Outra forma de ver as alterações que Percival utilizou em seu livro, foi por meio do git diff, conforme ilustrado abaixo. Linhas com + foram adicionadas
Basicamente as alterações incluem a criação de um objeto List; a atribuição de cada item a esse objeto por meio da propriedade .list. Em seguida, fizemos o teste se a lista foi salva e se os dois itens salvaram seu relacionamento com a lista.
Elaborado o teste, podemos executá-lo para iniciar o ciclo teste de unidade/código.
Para corrigir, precisamos implementar a classe List em lists/models.py, conforme abaixo:
Ao reexecutar os testes obtemos o seguinte erro:
Pela mensagem é um erro relacionado com a base de dados. Lembre-se que quando mudamos o modelo é necessário que façamos o migration para que as informações das tabelas do banco de dados sejam atualizadas a contento.
Feito isso o resultados dos testes passam a ser conforme abaixo:
O erro indica que não temos ainda o atributo .list na classe Item. Podemos incluí-lo da mesma forma que fizemos com o atributo .text.
Como alteramos novamente o modelo, nossos testes, se forem executados, iram nos lembrar que precisamos fazer uma migração.
Executada a migração agora nossos testes apresentam o erro abaixo:
Aparentemente, o tipo de dado do atributo .list. Como queremos estabelecer um relacionamento entre duas classes, o Django oferece um tipo de dado denominado ForeignKey e podemo mudar o tipo do atributo .list conforme mostrado abaixo. Mais informações sobre esse tipo de dado pode ser encontrada em https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ForeignKey.
Alterado o modelo devemos fazer a migração novamente. Entretanto, como a anterior não foi bem sucedida podemos removê-la antes. Cuidado, entretanto, ao remover migrações. Só o faça se as mesmas ainda não foram usadas.
Adaptando o Restante do Código ao Novo Modelo
Feita a correção e a migração acima, ao executar os testes novamente temos as seguintes mensagens de erro:
Ao todo, temos três erros de violação de restrição do tipo NOT_NULL. Como incluímos uma dependência entre Items e Lists, agora cada item tem que ter uma lista-pai associada a ele e, por isso, três de nossos testes unitários falharam.
O primeiro passo então é corrigir nossos testes unitários conforme abaixo. Veja as linhas 42 a 44 na qual é feita a associação entre o item e a lista.
Com isso, nossos testes avanças e ficam restando dois com falha, ambos relacionados ao POST para a inclusão de um novo item e nossa função de view que faz o tratamento a requisição também não faz a associação do item com um lista. A correção é dada nas linhas 13 e 14 abaixo:
Com isso, ao executar os testes de unidade obtemos sucesso na execução.
Novamente, mesmo tendo um resultado de sucesso nesse momento, Percival (2017) nos lembra de que o desenvolvimento, da forma como estamos fazendo, parece ser contraintuitiva. Criar uma lista a cada item sendo incluído parece estranho. Entretanto, ele nos alerta que mesmo dando vontade fazer tudo de uma única vez e já chegar ao código funcional que consideramos correto, é necessário seguir os passos do TDD. Ele nos lembra que devemos seguir o "Testing Goat!" ou nosso Bode dos Testes.
"Quando você estiver no alto de uma montanha, vai querer pensar cuidadosamente no lugar em que colocará cada pé, e dará um passo de cada vez, verificando, em cada etapa, se o local em que pisou não fará você cair de um penhasco." (Pervcival, 2017)
Desse modo, para nos assegurar que está tudo bem, ao executar nossos testes funcionais podemos observar que chagamos a um estado já conhecido e consistente.
Após as mudanças e a chegada a um ponto consistente com o que já tínhamos é um bom momento para colocarmos as mudanças sob controle de versão.
Ao verificar nossa lista de itens a cumprir, podemos riscar mais um.
Last updated
Was this helpful?