Flask + TDD exemplo prático #1

Após resolver de vez utilizar o tão famoso TDD em meus códigos Python, me deparei com algumas dificuldades para testar meu código no framework Flask.

Testar uma porção do código como uma classe que manipula dados é simples, porem caso eu queira testar algo mais complexo como autenticação do usuário, ou algum processamento que persiste e recupera dados do SGBD.

Pensei em utilizar algumas bibliotecas de “Mock”, porem nenhuma me deu o resultado esperado, até que recebi uma sugestão em utilizar o banco Sqlite em memória. A principio pareceu um pouco estranho até que eu resolvi testar.

Vamos ver um exemplo a seguir simplificado, apenas persistindo um valor e testando o mesmo, o foco aqui é a configuração do ambiente, para nos próximos posts podermos seguir.

Primeiro vamos criar um arquivo chamado models.py na pasta da aplicação e vamos colocar o seguinte codigo:

1
2
3
4
5
6
7
8
9
10
11
from flask.ext.sqlalchemy import SQLAlchemy, BaseQuery
 
 
db = SQLAlchemy()
 
class Usuario(db.Model):
    __tablename__ = "usuario"
    id = db.Column(db.Integer, primary_key=True)
    nome = db.Column(db.String(150))
    email = db.Column(db.String(250))
    senha = db.Column(db.String(250))

Perceba que apenas fiz uma instância de SQLAlchemy, porem não passei o contexto do Flask para o mesmo.

Agora vamos criar um arquivo chamado run_app_test.py que vai conter as especificações de teste.

1
2
3
4
5
6
7
8
9
10
from flask import Flask
from models import db
 
app = Flask(__name__)
app.secret_key = 'sua secret key aqui'
 
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
 
db.init_app(app)

Veja que ao invés de colocar um caminho físico para o SQLite eu coloquei a string de conexão para ele entender que é para carregar em memória, e passei para o “db.init_app” o contexto de app (Flask) fazendo assim aquela famosa injeção de dependência do jeito python

Agora criaremos uma pasta chamada Test, que é onde as nossas classes de testes irão ficar, após criar o diretório, crie dentro dele um arquivo chamado “usuario_test.py” e dentro dele iremos codificar nosso primeiro teste, que ficará da seguinte maneira

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from models import Usuario
from run_app_test import app, db
import unittest
 
class UsuarioTest(unittest.TestCase):
    def setUp(self):
        self.app = app
 
        with self.app.app_context():
            db.create_all()
 
    def test_criacao_de_usuario(self):
        usuario = Usuario()
        usuario.nome = "Usuario Test"
        usuario.email = "test@email.com"
        usuario.senha= "1234"
 
        #pega o contexto da aplicacao
        with self.app.app_context():
            db.session.add(usuario)
            db.session.commit()
 
            #valida se o id foi incrementado pelo banco de dados
            self.assertGreater(usuario.id, 0)

Temos alguns pontos que temos que esclarecer, nesse teste o método “setUp” sempre é chamado antes da execução dos métodos iniciados com “test_…” isso serve para que possa configurar o cenário básico do teste.

Temos o necessário para rodar o teste, porem para deixar os testes mais enxutos eu crio um arquivo chamado “test.py“, onde ficá os “imports” das classes de teste e a execução do teste em sí, que tem o seguinte formato:

1
2
3
4
5
6
from Tests.usuario_test import UsuarioTest
 
import unittest
 
if __name__ == '__main__':
	unittest.main()

Após criar basta rodar o comando “python test.py” que terá a seguinte saida:

hboechat:~/workspace (master) $ python test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.021s
 
OK

Esse post foi uma introdução de como eu configuro meu ambiente para testes, eu não segui os passos do TDD, pois esse não era o foco da postagem.
Na próxima postagem ensinarei mais alguns macetes, como testar sua api.

Obs: Os códigos fontes estão em https://github.com/hederson/flask-tdd-1 bons estudos 😉

Comecei a programar com 15 anos de idade e nunca mais parei.
Programador C# profissionalmente, e Python por opção.
%d blogueiros gostam disto: