mirror of
https://github.com/fhswf/aki_prj23_transparenzregister.git
synced 2025-06-22 04:23:56 +02:00
test: Adding unit tests
This commit is contained in:
542
poetry.lock
generated
542
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,7 @@ version = "0.1.0"
|
||||
loguru = "^0.7.0"
|
||||
matplotlib = "^3.7.1"
|
||||
plotly = "^5.14.1"
|
||||
pymongo = "^4.4.1"
|
||||
python = "^3.11"
|
||||
seaborn = "^0.12.2"
|
||||
selenium = "^4.10.0"
|
||||
@ -105,7 +106,7 @@ unfixable = ["B"]
|
||||
builtins-ignorelist = ["id"]
|
||||
|
||||
[tool.ruff.per-file-ignores]
|
||||
"tests/*.py" = ["S101"]
|
||||
"tests/*.py" = ["S101", "D100", "D101", "D107", "D103"]
|
||||
|
||||
[tool.ruff.pydocstyle]
|
||||
convention = "google"
|
||||
|
@ -1,15 +1,10 @@
|
||||
"""CompanyMongoService."""
|
||||
from models.company import Company
|
||||
from utils.company_service_interface import CompanyServiceInterface
|
||||
from utils.mongo import MongoConnector
|
||||
from aki_prj23_transparenzregister.models.company import Company, CompanyID
|
||||
from aki_prj23_transparenzregister.utils.mongo import MongoConnector
|
||||
|
||||
|
||||
class CompanyMongoService(CompanyServiceInterface):
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
CompanyServiceInterface (_type_): _description_
|
||||
"""
|
||||
class CompanyMongoService:
|
||||
"""_summary_."""
|
||||
|
||||
def __init__(self, connector: MongoConnector):
|
||||
"""_summary_.
|
||||
@ -28,7 +23,7 @@ class CompanyMongoService(CompanyServiceInterface):
|
||||
result = self.collection.find()
|
||||
return list(result)
|
||||
|
||||
def get_by_id(self, id: str) -> Company | None:
|
||||
def get_by_id(self, id: CompanyID) -> Company | None:
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
|
@ -1,51 +0,0 @@
|
||||
"""CompanyServiceInterface."""
|
||||
import abc
|
||||
|
||||
from models import Company
|
||||
|
||||
|
||||
class CompanyServiceInterface(abc.ABC):
|
||||
"""Generic abstract interface for CRUD operations of a Company.
|
||||
|
||||
Args:
|
||||
ABC (_type_): Abstract class
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_all(self) -> list[Company.Company]:
|
||||
"""_summary_.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: _description_
|
||||
|
||||
Returns:
|
||||
list[Company.Company]: _description_
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_by_id(self, id: Company.CompayID) -> Company.Company | None:
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
id (Company.CompayID): _description_
|
||||
|
||||
Raises:
|
||||
NotImplementedError: _description_
|
||||
|
||||
Returns:
|
||||
Company.Company | None: _description_
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def insert(self, company: Company.Company):
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
company (Company.Company): _description_
|
||||
|
||||
Raises:
|
||||
NotImplementedError: _description_
|
||||
"""
|
||||
raise NotImplementedError
|
@ -2,10 +2,6 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
import pymongo
|
||||
from models.news import News
|
||||
from utils.news_service_interface import (
|
||||
NewsServiceInterface,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -62,94 +58,3 @@ class MongoConnector:
|
||||
connection_string += f":{port}"
|
||||
connection_string = connection_string.replace("mongodb+srv", "mongodb")
|
||||
return pymongo.MongoClient(connection_string)
|
||||
|
||||
|
||||
class MongoNewsService(NewsServiceInterface):
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
NewsServiceInterface (_type_): _description_
|
||||
"""
|
||||
|
||||
def __init__(self, connector: MongoConnector):
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
connector (MongoConnector): _description_
|
||||
"""
|
||||
self.collection = connector.database["news"]
|
||||
|
||||
def get_all(self) -> list[News]:
|
||||
"""_summary_.
|
||||
|
||||
Returns:
|
||||
list[News]: _description_
|
||||
"""
|
||||
result = self.collection.find()
|
||||
return [MongoEntryTransformer.transform_outgoing(elem) for elem in result]
|
||||
|
||||
def get_by_id(self, id: str) -> News | None:
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
id (str): _description_
|
||||
|
||||
Returns:
|
||||
News | None: _description_
|
||||
"""
|
||||
result = list(self.collection.find({"_id": id}))
|
||||
if len(result) == 1:
|
||||
return MongoEntryTransformer.transform_outgoing(list(result)[0])
|
||||
return None
|
||||
|
||||
def insert(self, news: News):
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
news (News): _description_
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
return self.collection.insert_one(MongoEntryTransformer.transform_ingoing(news))
|
||||
|
||||
|
||||
class MongoEntryTransformer:
|
||||
"""_summary_.
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def transform_ingoing(news: News) -> dict:
|
||||
"""Convert a News object to a dictionary compatible with a MongoDB entry.
|
||||
|
||||
Args:
|
||||
news (News): News object to be transformed
|
||||
|
||||
Returns:
|
||||
dict: Transformed data with added _id field
|
||||
"""
|
||||
transport_object = news.to_dict()
|
||||
transport_object["_id"] = news.id
|
||||
del transport_object["id"]
|
||||
return transport_object
|
||||
|
||||
@staticmethod
|
||||
def transform_outgoing(data: dict) -> News:
|
||||
"""Reverse the transform_ingoing method.
|
||||
|
||||
Args:
|
||||
data (dict): dict from the MongoDB to be transformed
|
||||
|
||||
Returns:
|
||||
News: News entry based on MongoDB document
|
||||
"""
|
||||
return News(
|
||||
id=data["_id"],
|
||||
title=data["title"],
|
||||
date=data["date"],
|
||||
text=data["text"],
|
||||
source_url=data["source_url"],
|
||||
)
|
||||
|
@ -0,0 +1,94 @@
|
||||
"""MongoNewsService."""
|
||||
from aki_prj23_transparenzregister.models.news import News
|
||||
from aki_prj23_transparenzregister.utils.mongo import MongoConnector
|
||||
|
||||
|
||||
class MongoNewsService:
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
NewsServiceInterface (_type_): _description_
|
||||
"""
|
||||
|
||||
def __init__(self, connector: MongoConnector):
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
connector (MongoConnector): _description_
|
||||
"""
|
||||
self.collection = connector.database["news"]
|
||||
|
||||
def get_all(self) -> list[News]:
|
||||
"""_summary_.
|
||||
|
||||
Returns:
|
||||
list[News]: _description_
|
||||
"""
|
||||
result = self.collection.find()
|
||||
return [MongoEntryTransformer.transform_outgoing(elem) for elem in result]
|
||||
|
||||
def get_by_id(self, id: str) -> News | None:
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
id (str): _description_
|
||||
|
||||
Returns:
|
||||
News | None: _description_
|
||||
"""
|
||||
result = list(self.collection.find({"_id": id}))
|
||||
if len(result) == 1:
|
||||
return MongoEntryTransformer.transform_outgoing(list(result)[0])
|
||||
return None
|
||||
|
||||
def insert(self, news: News):
|
||||
"""_summary_.
|
||||
|
||||
Args:
|
||||
news (News): _description_
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
return self.collection.insert_one(MongoEntryTransformer.transform_ingoing(news))
|
||||
|
||||
|
||||
class MongoEntryTransformer:
|
||||
"""_summary_.
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def transform_ingoing(news: News) -> dict:
|
||||
"""Convert a News object to a dictionary compatible with a MongoDB entry.
|
||||
|
||||
Args:
|
||||
news (News): News object to be transformed
|
||||
|
||||
Returns:
|
||||
dict: Transformed data with added _id field
|
||||
"""
|
||||
transport_object = news.to_dict()
|
||||
transport_object["_id"] = news.id
|
||||
del transport_object["id"]
|
||||
return transport_object
|
||||
|
||||
@staticmethod
|
||||
def transform_outgoing(data: dict) -> News:
|
||||
"""Reverse the transform_ingoing method.
|
||||
|
||||
Args:
|
||||
data (dict): dict from the MongoDB to be transformed
|
||||
|
||||
Returns:
|
||||
News: News entry based on MongoDB document
|
||||
"""
|
||||
return News(
|
||||
id=data["_id"],
|
||||
title=data["title"],
|
||||
date=data["date"],
|
||||
text=data["text"],
|
||||
source_url=data["source_url"],
|
||||
)
|
@ -1,63 +0,0 @@
|
||||
"""NewsServiceInterface."""
|
||||
import abc
|
||||
|
||||
from models.news import News
|
||||
|
||||
|
||||
class NewsServiceInterface(abc.ABC):
|
||||
"""Generic abstract interface for a NewsService handling CRUD operations.
|
||||
|
||||
Args:
|
||||
ABC (_type_): Abstract class
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_all(self) -> list[News]:
|
||||
"""Get a list of all News articles.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: To be defined by child classes
|
||||
|
||||
Returns:
|
||||
list[News]: Results
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_by_id(self, id: str) -> News | None:
|
||||
"""Get an entry by an ID.
|
||||
|
||||
Args:
|
||||
id (str): ID identifying the entry
|
||||
|
||||
Raises:
|
||||
NotImplementedError: To be defined by child classes
|
||||
|
||||
Returns:
|
||||
News | None: Found object or None if no entry with ID found
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def insert(self, news: News):
|
||||
"""Insert a News entry into the DB.
|
||||
|
||||
Args:
|
||||
news (News): News object to be saved
|
||||
|
||||
Raises:
|
||||
NotImplementedError: To be defined by child classes
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def insert_many(self, news: list[News]):
|
||||
"""Inserts many documents at once.
|
||||
|
||||
Args:
|
||||
news (list[News]): List of News entries to be saved
|
||||
|
||||
Raises:
|
||||
NotImplementedError: To be defined by child classes
|
||||
"""
|
||||
raise NotImplementedError
|
@ -1,4 +1,4 @@
|
||||
"""Test Models.nes."""
|
||||
"""Test Models.nesws."""
|
||||
|
||||
|
||||
from aki_prj23_transparenzregister.models.news import News
|
||||
|
103
tests/utils/company_mongo_service_test.py
Normal file
103
tests/utils/company_mongo_service_test.py
Normal file
@ -0,0 +1,103 @@
|
||||
"""Test utils.company_mongo_service."""
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from aki_prj23_transparenzregister.models.company import Company
|
||||
from aki_prj23_transparenzregister.utils.company_mongo_service import (
|
||||
CompanyMongoService,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def mock_mongo_connector(mocker) -> Mock:
|
||||
"""Mock MongoConnector class.
|
||||
|
||||
Args:
|
||||
mocker (any): Library mocker
|
||||
|
||||
Returns:
|
||||
Mock: Mocked MongoConnector
|
||||
"""
|
||||
mock = Mock()
|
||||
mocker.patch(
|
||||
"aki_prj23_transparenzregister.utils.mongo.MongoConnector", return_value=mock
|
||||
)
|
||||
return mock
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def mock_collection() -> Mock:
|
||||
"""Mock mongo collection.
|
||||
|
||||
Returns:
|
||||
Mock: Mock object
|
||||
"""
|
||||
return Mock()
|
||||
|
||||
|
||||
def test_init(mock_mongo_connector, mock_collection):
|
||||
"""Test CompanyMongoService constructor.
|
||||
|
||||
Args:
|
||||
mock_mongo_connector (Mock): Mocked MongoConnector library
|
||||
mock_collection (Mock): Mocked pymongo collection
|
||||
"""
|
||||
mock_mongo_connector.database = {"companies": mock_collection}
|
||||
service = CompanyMongoService(mock_mongo_connector)
|
||||
assert service.collection == mock_collection
|
||||
|
||||
|
||||
def test_get_all(mock_mongo_connector, mock_collection):
|
||||
"""Test CompanyMongoService get_all method.
|
||||
|
||||
Args:
|
||||
mock_mongo_connector (Mock): Mocked MongoConnector library
|
||||
mock_collection (Mock): Mocked pymongo collection
|
||||
"""
|
||||
mock_mongo_connector.database = {"companies": mock_collection}
|
||||
service = CompanyMongoService(mock_mongo_connector)
|
||||
mock_result = [{"id": "42"}]
|
||||
mock_collection.find.return_value = mock_result
|
||||
assert service.get_all() == mock_result
|
||||
|
||||
|
||||
def test_by_id_no_result(mock_mongo_connector, mock_collection):
|
||||
"""Test CompanyMongoService get_by_id with no result.
|
||||
|
||||
Args:
|
||||
mock_mongo_connector (Mock): Mocked MongoConnector library
|
||||
mock_collection (Mock): Mocked pymongo collection
|
||||
"""
|
||||
mock_mongo_connector.database = {"companies": mock_collection}
|
||||
service = CompanyMongoService(mock_mongo_connector)
|
||||
mock_collection.find.return_value = []
|
||||
assert service.get_by_id("Does not exist") is None
|
||||
|
||||
|
||||
def test_by_id_result(mock_mongo_connector, mock_collection):
|
||||
"""Test CompanyMongoService get_by_id with result.
|
||||
|
||||
Args:
|
||||
mock_mongo_connector (Mock): Mocked MongoConnector library
|
||||
mock_collection (Mock): Mocked pymongo collection
|
||||
"""
|
||||
mock_mongo_connector.database = {"companies": mock_collection}
|
||||
service = CompanyMongoService(mock_mongo_connector)
|
||||
mock_entry = {"id": "Does exist", "vaue": 42}
|
||||
mock_collection.find.return_value = [mock_entry]
|
||||
assert service.get_by_id("Does exist") == mock_entry
|
||||
|
||||
|
||||
def test_insert(mock_mongo_connector, mock_collection):
|
||||
"""Test CompanyMongoService insert method.
|
||||
|
||||
Args:
|
||||
mock_mongo_connector (Mock): Mocked MongoConnector library
|
||||
mock_collection (Mock): Mocked pymongo collection
|
||||
"""
|
||||
mock_mongo_connector.database = {"companies": mock_collection}
|
||||
service = CompanyMongoService(mock_mongo_connector)
|
||||
mock_result = 42
|
||||
mock_collection.insert_one.return_value = mock_result
|
||||
assert service.insert(Company(None, None, "", "", [])) == mock_result
|
44
tests/utils/news_mongo_service_test.py
Normal file
44
tests/utils/news_mongo_service_test.py
Normal file
@ -0,0 +1,44 @@
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from aki_prj23_transparenzregister.utils.news_mongo_service import MongoNewsService
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def mock_mongo_connector(mocker) -> Mock:
|
||||
"""Mock MongoConnector class.
|
||||
|
||||
Args:
|
||||
mocker (any): Library mocker
|
||||
|
||||
Returns:
|
||||
Mock: Mocked MongoConnector
|
||||
"""
|
||||
mock = Mock()
|
||||
mocker.patch(
|
||||
"aki_prj23_transparenzregister.utils.mongo.MongoConnector", return_value=mock
|
||||
)
|
||||
return mock
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def mock_collection() -> Mock:
|
||||
"""Mock mongo collection.
|
||||
|
||||
Returns:
|
||||
Mock: Mock object
|
||||
"""
|
||||
return Mock()
|
||||
|
||||
|
||||
def test_init(mock_mongo_connector, mock_collection):
|
||||
"""Test CompanyMongoService constructor.
|
||||
|
||||
Args:
|
||||
mock_mongo_connector (Mock): Mocked MongoConnector library
|
||||
mock_collection (Mock): Mocked pymongo collection
|
||||
"""
|
||||
mock_mongo_connector.database = {"news": mock_collection}
|
||||
service = MongoNewsService(mock_mongo_connector)
|
||||
assert service.collection == mock_collection
|
Reference in New Issue
Block a user