Created
December 16, 2023 21:00
-
-
Save MM-coder/ad200d82ea335f0f76b323ae75c3a79f to your computer and use it in GitHub Desktop.
Unit tests for the FeiraVirtual project
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import random | |
import re | |
from pathlib import Path | |
import pytest | |
import string | |
from classes import Utilizador, Avaliacao, Artigo, FeiraVirtual, Mercado | |
def _random_string(length: int) -> str: | |
"""Gera uma ‘string’ aletória de um dado comprimento""" | |
characters = string.ascii_letters + string.digits | |
return "".join(random.choice(characters) for _ in range(length)) | |
class TestUtilizador: | |
@pytest.fixture | |
def utilizador(self): | |
"""Fixture que cria um utilizador para testar.""" | |
artigo_exemplo = Artigo( | |
nome="Computador", preco=10.0, tipologia="Tecnologia", quantidade=1 | |
) | |
avaliacao_exemplo = Avaliacao(estrelas=4, comentario="Exemplo") | |
return Utilizador( | |
nome="Mauro", | |
interesses=["Tecnologia"], | |
artigos_disponiveis=[artigo_exemplo], | |
avaliacoes=[avaliacao_exemplo], | |
) | |
def test_editar_conta(self, utilizador): | |
"""Testa editar interesses dos utilizadores""" | |
novos_interesses = ["Gaming", "Tecnologia"] | |
novos_artigos = [ | |
Artigo(nome="Computador", preco=10.0, tipologia="Tecnologia", quantidade=1) | |
] | |
utilizador.editar_conta(novos_interesses, novos_artigos) | |
assert "Gaming" in utilizador.interesses | |
assert novos_artigos[0] in utilizador.artigos_disponiveis | |
# O interesse já existente deverá permanecer | |
assert "Tecnologia" in utilizador.interesses | |
def test_deixar_avaliacao(self, utilizador): | |
"""Testa dexiar avaliações válidas e inválidas.""" | |
utilizador.deixar_avaliacao(estrelas=4, comentario="Bom") | |
last_avaliacao = utilizador.avaliacoes[-1] | |
assert last_avaliacao.estrelas == 4 | |
assert last_avaliacao.comentario == "Bom" | |
with pytest.raises(ValueError): | |
utilizador.deixar_avaliacao(estrelas=6, comentario="Muito Bom") | |
def test_alterar_pycoins(self, utilizador): | |
"""Testa atualizar pycoins com valores válidos e inválidos.""" | |
# Apenas chamar o random uma vez | |
integer: int = random.randint(0, 100000) | |
utilizador.alterar_pycoins(integer) | |
assert utilizador.pycoins == integer | |
utilizador.alterar_pycoins(-integer) | |
assert ( | |
utilizador.pycoins == 0 | |
), "O programa não deve aceitar valores de pycoins negativos" | |
class TestArtigo: | |
# Método para configurar um artigo de teste antes de cada método | |
@pytest.fixture | |
def artigo(self): | |
"""Fixture que cria um artigo para testar.""" | |
return Artigo( | |
nome="Artigo Teste", preco=10.0, tipologia="Tipo Teste", quantidade=5 | |
) | |
def test_editar_nome(self, artigo): | |
"""Testa a alteração do nome de um artigo.""" | |
nome_aletorio = _random_string(random.randint(1, 100)) | |
artigo.editar_nome(nome_aletorio) | |
assert artigo.nome == nome_aletorio | |
artigo.editar_nome("") # Testa com nome vazio | |
assert artigo.nome == "" | |
def test_ajustar_preco(self, artigo): | |
"""Testa a alteração do preço por uma percentagem.""" | |
preco_atual = artigo.preco | |
percentagem_aletoria = random.randint(0, 100) | |
# Deverá reduzir o preço para metade | |
artigo.ajustar_preco(percentagem_aletoria) | |
assert artigo.preco == preco_atual * (percentagem_aletoria / 100) | |
with pytest.raises(ValueError): | |
# Testa com valor fora do intervalo | |
artigo.ajustar_preco(-percentagem_aletoria) | |
def test_editar_preco(self, artigo): | |
"""Testa a definição de um novo preço para o artigo.""" | |
integer: int = random.randint(0, 100000) | |
artigo.editar_preco(integer) | |
assert artigo.preco == integer | |
artigo.editar_preco(-integer) # Testa com preço negativo | |
assert artigo.preco == 0 | |
def test_editar_quantidade(self, artigo): | |
"""Testa a alteração da quantidade de um artigo.""" | |
# Apenas chamar o random uma vez | |
integer: int = random.randint(0, 100000) | |
artigo.editar_quantidade(integer) | |
assert artigo.quantidade == integer | |
artigo.editar_quantidade(-integer) # Testa com quantidade negativa | |
assert artigo.quantidade == 0 | |
def test_editar_tipo(self, artigo): | |
"""Testa a alteração da tipologia de um artigo.""" | |
tipo_aletorio = _random_string(random.randint(1, 100)) | |
artigo.editar_tipo(tipo_aletorio) | |
assert artigo.tipologia == tipo_aletorio | |
artigo.editar_tipo("") # Teste com tipo vazio | |
assert artigo.tipologia == "" | |
class TestFeiraVirtual: | |
@pytest.fixture | |
def feira(self): | |
"""Cria uma instância de FeiraVirtual para uso nos testes.""" | |
feira = FeiraVirtual(utilizadores=[], mercado=Mercado()) | |
return feira | |
def test_registar_utilizador(self, feira): | |
"""Testa o registro de um novo utilizador.""" | |
nome_aletorio = _random_string(random.randint(1, 100)) | |
feira.registar_utilizador( | |
nome=nome_aletorio, interesses=["Tecnologia", "Livros"] | |
) | |
assert len(feira.utilizadores) == 1 | |
assert feira.utilizadores[0].nome == nome_aletorio | |
# Testa registar um novo utilizador com um nome já existente | |
with pytest.raises(ValueError): | |
feira.registar_utilizador(nome=nome_aletorio, interesses=["Cinema"]) | |
def test_eliminar_conta(self, feira): | |
"""Testa a eliminação de uma conta.""" | |
nome_aletorio = _random_string(random.randint(1, 100)) | |
feira.registar_utilizador(nome=nome_aletorio, interesses=["Moda"]) | |
assert feira.eliminar_conta(nome_utilizador=nome_aletorio) == 0 | |
assert feira.eliminar_conta(nome_utilizador=nome_aletorio) == 1 | |
def test_calcular_reputacao(self, feira): | |
"""Testa o cálculo da reputação de um utilizador.""" | |
nome_aletorio = _random_string(random.randint(1, 100)) | |
feira.registar_utilizador( | |
nome=nome_aletorio, interesses=["Arte"], artigos_disponiveis=[] | |
) | |
assert ( | |
feira.calcular_reputacao(nome_utilizador=nome_aletorio) == 0 | |
) # Sem avaliações | |
# Adicionar avaliações manualmente | |
utilizador = feira.utilizadores[0] | |
utilizador.avaliacoes = [ | |
Avaliacao(estrelas=4, comentario="Bom"), | |
Avaliacao(estrelas=5, comentario="Excelente"), | |
] | |
assert feira.calcular_reputacao(nome_utilizador=nome_aletorio) == 4.5 | |
assert ( | |
feira.calcular_reputacao( | |
nome_utilizador=_random_string(random.randint(1, 100)) | |
) | |
== -1 | |
) # Utilizador | |
# inexistente | |
def test_importar_utilizadores_exemplo(self, feira, tmp_path: Path): | |
"""Testa a importação de utilizadores com o exemplo dado""" | |
exemplo = ( | |
"nome;[interesse_1,interesse_2,…];[nome_artigo_1,preço,tipologia,quantidade&nome_artigo_2,…]\nAna;[" | |
"tecnologia,moda];[telemóvel,5,tecnologia,1&raquete de ténis,10,desporto,2]\nManuel;[arte," | |
"viagens];[quadro Van Gogh,50,arte,1&guitarra,10,música,1&PS5,25,jogos,4]\nSilvia;[" | |
"livros];\nSofia;[jogos,música];[panela elétrica,8,cozinha,1&bilhete de avião para as Caraíbas,39," | |
"viagens,2]\nAntónio;[viagens,cinema];[bola de futebol,16,desporto,1]\nPedro;[cinema,culinária," | |
"tecnologia];[bicicleta,30,desporto,2]\nRaquel;[tecnologia,desporto,arte,livros];[escultura em " | |
"madeira,40,arte,1]\nPaulo;[livros];[Monopoly,10,jogos,1&coluna,19,musica,1&frigideira,9," | |
"culinária,5]\nJoaquim;[jogos,música,cinema];[vinil best of k-pop,8,musica,2]\nCristina;[moda," | |
"música,tecnologia];[casaco de inverno,22,moda,1]" | |
) | |
ficheiro_temporario = tmp_path / "exemplo.txt" | |
with open(ficheiro_temporario, "w+") as fp: | |
fp.write(exemplo) | |
feira.importar_utilizadores(ficheiro_temporario) | |
assert len(feira.utilizadores) == 10 and [ | |
u.nome for u in feira.utilizadores | |
] == [ | |
"Ana", | |
"Manuel", | |
"Silvia", | |
"Sofia", | |
"António", | |
"Pedro", | |
"Raquel", | |
"Paulo", | |
"Joaquim", | |
"Cristina", | |
] | |
assert all([u.pycoins == 50 for u in feira.utilizadores]) | |
def test_exportar_artigos_preco(self, feira, tmp_path): | |
"""Testa a exportação de artigos ordenados por quantidade.""" | |
artigo1 = Artigo(nome="Artigo1", preco=1.0, tipologia="Tipo1", quantidade=1) | |
artigo2 = Artigo(nome="Artigo2", preco=1.0, tipologia="Tipo2", quantidade=2) | |
artigo3 = Artigo(nome="Artigo3", preco=1.0, tipologia="Tipo3", quantidade=3) | |
feira.mercado.artigos = [artigo1, artigo2, artigo3] | |
nome_ficheiro = tmp_path / "artigos_exportados.txt" | |
# Exportar os artigos | |
feira.exportar_artigos_preco(nome_ficheiro) | |
# Verificar se o ficheiro foi criado | |
assert os.path.exists(nome_ficheiro) | |
# Lê o conteúdo do ficheiro e verifica se está ordenado por preço | |
with open(nome_ficheiro, "r") as ficheiro: | |
conteudo = ficheiro.read() | |
# Verifica a ordem - menor para maior preço | |
assert ( | |
conteudo.find("Artigo1") | |
< conteudo.find("Artigo2") | |
< conteudo.find("Artigo3") | |
) | |
for linha in ficheiro.readlines(): | |
# Verifica o formato | |
assert re.match( | |
r"^(\w+,\d+(\.\d+)?,\w+,\d+)", linha | |
), "A linha não tem o formato correcto" | |
def test_colocar_artigo_para_venda_novo_artigo(self, feira): | |
"""Testa adicionar um novo artigo à venda.""" | |
vendedor = Utilizador( | |
nome="Vendedor1", interesses=["Tech"], artigos_disponiveis=[] | |
) | |
artigo_novo = Artigo( | |
nome="Artigo1", preco=100.0, tipologia="Tipo1", quantidade=5 | |
) | |
feira.utilizadores.append(vendedor) | |
feira.colocar_artigo_para_venda("Vendedor1", artigo_novo, 100.0) | |
assert artigo_novo in vendedor.artigos_disponiveis | |
assert artigo_novo in feira.mercado.artigos | |
def test_colocar_artigo_para_venda_preco_ajustado(self, feira): | |
"""Testa se o preço do artigo é ajustado para o preço menor.""" | |
vendedor = Utilizador( | |
nome="Vendedor2", interesses=["Moda"], artigos_disponiveis=[] | |
) | |
artigo_mercado = Artigo( | |
nome="Artigo2", preco=80.0, tipologia="Tipo2", quantidade=8 | |
) | |
artigo_venda = Artigo( | |
nome="Artigo2", preco=100.0, tipologia="Tipo2", quantidade=3 | |
) | |
feira.utilizadores.append(vendedor) | |
feira.mercado.artigos.append(artigo_mercado) | |
feira.colocar_artigo_para_venda("Vendedor2", artigo_venda, 100.0) | |
# O preço do artigo vendido deve ser ajustado para 80.0 | |
assert artigo_venda.preco == 80.0 | |
def test_regularizacao_mercado_apos_venda(self, feira): | |
"""Testa a regularização do mercado após uma venda.""" | |
vendedor = Utilizador( | |
nome="Vendedor3", interesses=["Livros"], artigos_disponiveis=[] | |
) | |
preco = random.randint(1, 100) | |
artigo = Artigo( | |
nome="Artigo3", | |
preco=preco, | |
tipologia="Tipo3", | |
quantidade=random.randint(1, 3), | |
) # Quantidade <= 3 | |
feira.utilizadores.append(vendedor) | |
feira.colocar_artigo_para_venda("Vendedor3", artigo, preco) | |
# O preço do artigo deve aumentar em 25% devido à regularização do mercado | |
preco_esperado = preco * 1.25 | |
assert artigo.preco == preco_esperado | |
class TestMercado: | |
@pytest.fixture | |
def mercado(self): | |
mercado = Mercado(artigos=[]) | |
return mercado | |
def test_adicionar_artigo_novo(self, mercado): | |
"""Testa a adição de um novo artigo ao mercado.""" | |
nome_aletorio = _random_string(random.randint(1, 100)) | |
artigo_novo = Artigo( | |
nome=nome_aletorio, preco=10.0, tipologia="Tipo1", quantidade=1 | |
) | |
mercado.adicionar_artigo(artigo_novo) | |
assert len(mercado.artigos) == 1 | |
assert mercado.artigos[0].nome == nome_aletorio | |
assert mercado.artigos[0].quantidade == 1 | |
def test_adicionar_artigo_existente(self, mercado): | |
"""Testa a adição de quantidade a um artigo já existente no mercado.""" | |
nome_aletorio = _random_string(random.randint(1, 100)) | |
tipo_aletorio = _random_string(random.randint(1, 100)) | |
artigo_existente = Artigo( | |
nome=nome_aletorio, preco=15.0, tipologia=tipo_aletorio, quantidade=2 | |
) | |
mercado.adicionar_artigo(artigo_existente) | |
# Adiciona novamente o mesmo artigo com quantidade adicional | |
artigo_adicional = Artigo( | |
nome=nome_aletorio, preco=15.0, tipologia=tipo_aletorio, quantidade=3 | |
) | |
mercado.adicionar_artigo(artigo_adicional) | |
assert len(mercado.artigos) == 1 # Deve continuar com um artigo apenas | |
# Quantidade deve ser a soma das duas adições | |
assert mercado.artigos[0].quantidade == 5 | |
def test_nomes_artigos(self, mercado): | |
"""Testa se a propriedade nomes_artigos retorna os nomes dos artigos corretamente.""" | |
nome1, nome2 = ( | |
_random_string(random.randint(1, 100)), | |
_random_string(random.randint(1, 100)), | |
) | |
tipo = _random_string(random.randint(1, 100)) | |
artigo1 = Artigo(nome=nome1, preco=20.0, tipologia=tipo, quantidade=1) | |
artigo2 = Artigo(nome=nome2, preco=25.0, tipologia=tipo, quantidade=2) | |
mercado.adicionar_artigo(artigo1) | |
mercado.adicionar_artigo(artigo2) | |
nomes_esperados = {nome1, nome2} | |
assert set(mercado.nomes_artigos) == {n.casefold() for n in nomes_esperados} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment