Skip to content

Commit 361a864

Browse files
committed
Merge branch 'TT-353-Create-V2-Activities-DAO' into TT-352-Create-V2-read-activites-flask-endpoint
2 parents 2ce4987 + 1f92569 commit 361a864

File tree

7 files changed

+120
-175
lines changed

7 files changed

+120
-175
lines changed

V2/source/daos/activities_dao.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from V2.source.dtos.activity import Activity
2+
import abc
3+
import typing
4+
5+
6+
class ActivitiesDao(abc.ABC):
7+
@abc.abstractmethod
8+
def get_by_id(self, id: str) -> Activity:
9+
pass
10+
11+
@abc.abstractmethod
12+
def get_all(self) -> typing.List[Activity]:
13+
pass

V2/source/daos/activities_dao_interface.py

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,35 @@
1-
from V2.source.daos.activities_dao_interface import ActivitiesDaoInterface
2-
from V2.source.dtos.activity import ActivityDto
3-
from http import HTTPStatus
1+
from V2.source.daos.activities_dao import ActivitiesDao
2+
from V2.source.dtos.activity import Activity
43
import json
4+
import typing
55

66

7-
class ActivitiesJsonDao(ActivitiesDaoInterface):
7+
class ActivitiesJsonDao(ActivitiesDao):
88
def __init__(self, json_data_file_path: str):
99
self.json_data_file_path = json_data_file_path
10-
self.activity_keys = ActivityDto.__dataclass_fields__.keys()
11-
12-
def get_by_id(self, id: str) -> ActivityDto:
13-
activities = self.__get_activities_from_file()
14-
15-
try:
16-
activity = next(
17-
(
18-
activity
19-
for activity in activities
20-
if activity.get('id') == id
21-
)
22-
)
23-
except Exception:
24-
return HTTPStatus.NOT_FOUND
25-
26-
activity_dto = self.__create_activity_dto(activity)
10+
self.activity_keys = Activity.__dataclass_fields__.keys()
11+
12+
def get_by_id(self, activity_id: str) -> Activity:
13+
activities_grouped_by_id = {
14+
activity.get('id'): activity
15+
for activity in self.__get_activities_from_file()
16+
}
17+
activity = activities_grouped_by_id.get(activity_id)
18+
activity_dto = (
19+
self.__create_activity_dto(activity) if activity else None
20+
)
2721

2822
return activity_dto
2923

30-
def get_all(self) -> list:
31-
activities = self.__get_activities_from_file()
32-
list_activities = []
33-
34-
for activity in activities:
35-
activity = self.__create_activity_dto(activity)
36-
list_activities.append(activity)
24+
def get_all(self) -> typing.List[Activity]:
25+
all_activities = self.__get_activities_from_file()
26+
activity_dtos = [
27+
self.__create_activity_dto(activity) for activity in all_activities
28+
]
3729

38-
return list_activities
30+
return activity_dtos
3931

40-
def __get_activities_from_file(self) -> list:
32+
def __get_activities_from_file(self) -> typing.List[dict]:
4133
try:
4234
file = open(self.json_data_file_path)
4335
activities = json.load(file)
@@ -48,7 +40,7 @@ def __get_activities_from_file(self) -> list:
4840
except FileNotFoundError:
4941
return []
5042

51-
def __create_activity_dto(self, activity: dict) -> ActivityDto:
43+
def __create_activity_dto(self, activity: dict) -> Activity:
5244
activity = {key: activity.get(key) for key in self.activity_keys}
53-
activity_dto = ActivityDto(**activity)
45+
activity_dto = Activity(**activity)
5446
return activity_dto

V2/source/dtos/activity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44
@dataclass(frozen=True)
5-
class ActivityDto:
5+
class Activity:
66
id: str
77
name: str
88
description: str
Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
from V2.source.daos.activities_dao_interface import ActivitiesDaoInterface
2-
from V2.source.dtos.activity import ActivityDto
1+
from V2.source.daos.activities_dao import ActivitiesDao
2+
from V2.source.dtos.activity import Activity
3+
import typing
34

45

56
class ActivityService:
6-
def __init__(self, activities_dao: ActivitiesDaoInterface):
7+
def __init__(self, activities_dao: ActivitiesDao):
78
self.activities_dao = activities_dao
89

9-
def get_by_id(self, id: str) -> ActivityDto:
10-
activity_dto = self.activities_dao.get_by_id(id)
11-
return activity_dto
10+
def get_by_id(self, activity_id: str) -> Activity:
11+
return self.activities_dao.get_by_id(activity_id)
1212

13-
def get_all(self) -> list:
14-
list_activities = self.activities_dao.get_all()
15-
return list_activities
13+
def get_all(self) -> typing.List[Activity]:
14+
return self.activities_dao.get_all()
Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,85 @@
11
from V2.source.daos.activities_json_dao import ActivitiesJsonDao
2-
from V2.source.dtos.activity import ActivityDto
3-
from http import HTTPStatus
2+
from V2.source.dtos.activity import Activity
3+
from faker import Faker
44
import json
5+
import pytest
6+
import typing
57

68

7-
OPEN_FILE = 'builtins.open'
9+
@pytest.fixture(name='create_fake_activities')
10+
def _create_fake_activities(mocker) -> typing.List[Activity]:
11+
def _creator(activities):
12+
read_data = json.dumps(activities)
13+
mocker.patch('builtins.open', mocker.mock_open(read_data=read_data))
14+
return [Activity(**activity) for activity in activities]
815

16+
return _creator
917

10-
def test_get_by_id__return_activity_dto__when_find_activity_that_matches_its_id(
11-
mocker,
18+
19+
def test_get_by_id__returns_an_activity_dto__when_found_one_activity_that_matches_its_id(
20+
create_fake_activities,
1221
):
13-
activities_json_dao = ActivitiesJsonDao('non-important-path')
14-
activities = [
15-
{
16-
"name": "test_name",
17-
"description": "test_description",
18-
"tenant_id": "test_tenant_id",
19-
"id": "test_id",
20-
"deleted": "test_deleted",
21-
"status": "test_status",
22-
}
23-
]
24-
read_data = json.dumps(activities)
25-
activity_dto = ActivityDto(**activities.pop())
26-
27-
mocker.patch(OPEN_FILE, mocker.mock_open(read_data=read_data))
22+
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
23+
activities = create_fake_activities(
24+
[
25+
{
26+
"name": "test_name",
27+
"description": "test_description",
28+
"tenant_id": "test_tenant_id",
29+
"id": "test_id",
30+
"deleted": "test_deleted",
31+
"status": "test_status",
32+
}
33+
]
34+
)
35+
activity_dto = activities.pop()
36+
2837
result = activities_json_dao.get_by_id(activity_dto.id)
2938

3039
assert result == activity_dto
3140

3241

33-
def test__get_by_id__return_httpstatus_not_found__when_no_activity_matches_its_id(
34-
mocker,
42+
def test__get_by_id__returns_none__when_no_activity_matches_its_id(
43+
create_fake_activities,
3544
):
36-
activities_json_dao = ActivitiesJsonDao('non-important-path')
37-
activities = []
38-
read_data = json.dumps(activities)
45+
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
46+
create_fake_activities([])
3947

40-
mocker.patch(OPEN_FILE, mocker.mock_open(read_data=read_data))
41-
result = activities_json_dao.get_by_id('non-important-id')
48+
result = activities_json_dao.get_by_id(Faker().uuid4())
4249

43-
assert result == HTTPStatus.NOT_FOUND
50+
assert result == None
4451

4552

46-
def test_get_all__return_list_of_activity_dto__when_find_one_or_more_activities(
47-
mocker,
53+
def test__get_all__returns_a_list_of_activity_dto_objects__when_one_or_more_activities_are_found(
54+
create_fake_activities,
4855
):
49-
activities_json_dao = ActivitiesJsonDao('non-important-path')
50-
activity = {
51-
"name": "test_name",
52-
"description": "test_description",
53-
"tenant_id": "test_tenant_id",
54-
"id": "test_id",
55-
"deleted": "test_deleted",
56-
"status": "test_status",
57-
}
56+
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
5857
number_of_activities = 3
59-
activity_dto = ActivityDto(**activity)
60-
list_activities_dto = [activity_dto] * number_of_activities
61-
activities = [activity] * number_of_activities
62-
read_data = json.dumps(activities)
58+
activities = create_fake_activities(
59+
[
60+
{
61+
"name": "test_name",
62+
"description": "test_description",
63+
"tenant_id": "test_tenant_id",
64+
"id": "test_id",
65+
"deleted": "test_deleted",
66+
"status": "test_status",
67+
}
68+
]
69+
* number_of_activities
70+
)
6371

64-
mocker.patch(OPEN_FILE, mocker.mock_open(read_data=read_data))
6572
result = activities_json_dao.get_all()
6673

67-
assert result == list_activities_dto
74+
assert result == activities
6875

6976

70-
def test_get_all__return_empty_list__when_doesnt_found_any_activities(mocker):
71-
activities_json_dao = ActivitiesJsonDao('non-important-path')
72-
activities = []
73-
read_data = json.dumps(activities)
77+
def test_get_all__returns_an_empty_list__when_doesnt_found_any_activities(
78+
create_fake_activities,
79+
):
80+
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
81+
activities = create_fake_activities([])
7482

75-
mocker.patch(OPEN_FILE, mocker.mock_open(read_data=read_data))
7683
result = activities_json_dao.get_all()
7784

7885
assert result == activities
Lines changed: 17 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,28 @@
11
from V2.source.services.activity_service import ActivityService
2-
from V2.source.daos.activities_dao_interface import ActivitiesDaoInterface
3-
from V2.source.dtos.activity import ActivityDto
4-
from http import HTTPStatus
2+
from faker import Faker
53

64

7-
def test__get_by_id__return_activity_dto__when_find_activity_that_matches_its_id(
8-
mocker,
9-
):
10-
activity_service = ActivityService(ActivitiesDaoInterface)
11-
activity = {
12-
"name": "test_name",
13-
"description": "test_description",
14-
"tenant_id": "test_tenant_id",
15-
"id": "test_id",
16-
"deleted": "test_deleted",
17-
"status": "test_status",
18-
}
19-
activity_dto = ActivityDto(**activity)
20-
21-
activities_dao_mock = mocker.patch.object(
22-
ActivitiesDaoInterface, 'get_by_id'
5+
def test__get_all__uses_the_activity_dao__to_retrieve_activities(mocker):
6+
expected_activities = mocker.Mock()
7+
activity_dao = mocker.Mock(
8+
get_all=mocker.Mock(return_value=expected_activities)
239
)
24-
activities_dao_mock.return_value = activity_dto
25-
result = activity_service.get_by_id(activity.get('id'))
10+
activity_service = ActivityService(activity_dao)
2611

27-
assert result == activity_dto
12+
actual_activities = activity_service.get_all()
2813

14+
assert activity_dao.get_all.called
15+
assert expected_activities == actual_activities
2916

30-
def test__get_by_id__return_httpstatus_not_found__when_no_activity_matches_its_id(
31-
mocker,
32-
):
33-
activity_service = ActivityService(ActivitiesDaoInterface)
3417

35-
activities_dao_mock = mocker.patch.object(
36-
ActivitiesDaoInterface, 'get_by_id'
18+
def test__get_by_id__uses_the_activity_dao__to_retrieve_one_ativity(mocker):
19+
expected_activity = mocker.Mock()
20+
activity_dao = mocker.Mock(
21+
get_by_id=mocker.Mock(return_value=expected_activity)
3722
)
38-
activities_dao_mock.return_value = HTTPStatus.NOT_FOUND
39-
40-
result = activity_service.get_by_id('non-important-id')
41-
42-
assert result == HTTPStatus.NOT_FOUND
23+
activity_service = ActivityService(activity_dao)
4324

25+
actual_activity = activity_service.get_by_id(Faker().uuid4())
4426

45-
def test__get_all__return_list_of_activity_dto__when_find_one_or_more_activities(
46-
mocker,
47-
):
48-
activity_service = ActivityService(ActivitiesDaoInterface)
49-
activity = {
50-
"name": "test_name",
51-
"description": "test_description",
52-
"tenant_id": "test_tenant_id",
53-
"id": "test_id",
54-
"deleted": "test_deleted",
55-
"status": "test_status",
56-
}
57-
number_of_activities = 3
58-
activity_dto = ActivityDto(**activity)
59-
list_activities_dto = [activity_dto] * number_of_activities
60-
61-
activities_dao_mock = mocker.patch.object(
62-
ActivitiesDaoInterface, 'get_all'
63-
)
64-
activities_dao_mock.return_value = list_activities_dto
65-
result = activity_service.get_all()
66-
67-
assert result == list_activities_dto
68-
69-
70-
def test__get_all__return_empty_list__when_doesnt_found_any_activities(
71-
mocker,
72-
):
73-
activity_service = ActivityService(ActivitiesDaoInterface)
74-
activities = []
75-
76-
activities_dao_mock = mocker.patch.object(
77-
ActivitiesDaoInterface, 'get_all'
78-
)
79-
activities_dao_mock.return_value = activities
80-
result = activity_service.get_all()
81-
82-
assert result == activities
27+
assert activity_dao.get_by_id.called
28+
assert expected_activity == actual_activity

0 commit comments

Comments
 (0)