-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Application Service Enhancements (#457)
- Introduce `use_case` decorator to mark methods in App service - Wrap application service method calls within a UoW - Link Application Service to an aggregate with `part_of`
- Loading branch information
Showing
9 changed files
with
233 additions
and
32 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file was deleted.
Oops, something went wrong.
54 changes: 54 additions & 0 deletions
54
tests/application_service/test_application_service_call.py
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
from protean.core.aggregate import BaseAggregate | ||
from protean.core.application_service import BaseApplicationService, use_case | ||
from protean.core.event import BaseEvent | ||
from protean.fields import Identifier, String | ||
from protean.utils.globals import current_domain | ||
|
||
|
||
class User(BaseAggregate): | ||
email = String() | ||
name = String() | ||
status = String(choices=["INACTIVE", "ACTIVE", "ARCHIVED"], default="INACTIVE") | ||
|
||
def activate(self): | ||
self.status = "ACTIVE" | ||
|
||
|
||
class Registered(BaseEvent): | ||
user_id = Identifier() | ||
email = String() | ||
name = String() | ||
|
||
|
||
class UserApplicationServices(BaseApplicationService): | ||
@use_case | ||
def register_user(self, email: str, name: str) -> Identifier: | ||
user = User(email=email, name=name) | ||
user.raise_(Registered(user_id=user.id, email=user.email, name=user.name)) | ||
current_domain.repository_for(User).add(user) | ||
|
||
return user.id | ||
|
||
@use_case | ||
def activate_user(sefl, user_id: Identifier) -> None: | ||
user = current_domain.repository_for(User).get(user_id) | ||
user.activate() | ||
current_domain.repository_for(User).add(user) | ||
|
||
|
||
def test_application_service_method_invocation(test_domain): | ||
test_domain.register(User) | ||
test_domain.register(UserApplicationServices, part_of=User) | ||
test_domain.register(Registered, part_of=User) | ||
test_domain.init(traverse=False) | ||
|
||
app_services_obj = UserApplicationServices() | ||
|
||
user_id = app_services_obj.register_user( | ||
email="[email protected]", name="John Doe" | ||
) | ||
assert user_id is not None | ||
|
||
app_services_obj.activate_user(user_id) | ||
user = current_domain.repository_for(User).get(user_id) | ||
assert user.status == "ACTIVE" |
50 changes: 50 additions & 0 deletions
50
tests/application_service/test_application_service_options.py
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import pytest | ||
|
||
from protean.core.aggregate import BaseAggregate | ||
from protean.core.application_service import BaseApplicationService | ||
from protean.core.event import BaseEvent | ||
from protean.core.event_handler import BaseEventHandler | ||
from protean.exceptions import IncorrectUsageError, NotSupportedError | ||
from protean.fields import Identifier, String | ||
from protean.utils.globals import current_domain | ||
|
||
|
||
class User(BaseAggregate): | ||
email = String() | ||
name = String() | ||
|
||
|
||
def test_that_base_command_handler_cannot_be_instantianted(): | ||
with pytest.raises(NotSupportedError): | ||
BaseApplicationService() | ||
|
||
|
||
def test_part_of_specified_during_registration(test_domain): | ||
class UserApplicationService(BaseApplicationService): | ||
pass | ||
|
||
test_domain.register(UserApplicationService, part_of=User) | ||
assert UserApplicationService.meta_.part_of == User | ||
|
||
|
||
def test_part_of_defined_via_annotation( | ||
test_domain, | ||
): | ||
@test_domain.application_service(part_of=User) | ||
class UserApplicationService: | ||
pass | ||
|
||
assert UserApplicationService.meta_.part_of == User | ||
|
||
|
||
def test_part_of_is_mandatory(test_domain): | ||
class UserApplicationService(BaseApplicationService): | ||
pass | ||
|
||
with pytest.raises(IncorrectUsageError) as exc: | ||
test_domain.register(UserApplicationService) | ||
|
||
assert ( | ||
exc.value.args[0] | ||
== "Application Service `UserApplicationService` needs to be associated with an aggregate" | ||
) |
This file contains 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
52 changes: 52 additions & 0 deletions
52
tests/application_service/test_uow_around_application_services.py
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import mock | ||
|
||
from protean.core.aggregate import BaseAggregate | ||
from protean.core.application_service import BaseApplicationService, use_case | ||
from protean.core.event import BaseEvent | ||
from protean.fields import Identifier, String | ||
from protean.utils.globals import current_domain | ||
|
||
|
||
class User(BaseAggregate): | ||
email = String() | ||
name = String() | ||
|
||
|
||
class Registered(BaseEvent): | ||
user_id = Identifier() | ||
email = String() | ||
name = String() | ||
|
||
|
||
class UserApplicationServices(BaseApplicationService): | ||
@use_case | ||
def register_user(self, email: str, name: str) -> Identifier: | ||
user = User(email=email, name=name) | ||
user.raise_(Registered(user_id=user.id, email=user.email, name=user.name)) | ||
current_domain.repository_for(User).add(user) | ||
|
||
return user.id | ||
|
||
|
||
@mock.patch("protean.utils.mixins.UnitOfWork.__enter__") | ||
@mock.patch("protean.utils.mixins.UnitOfWork.__exit__") | ||
def test_that_method_is_enclosed_in_uow(mock_exit, mock_enter, test_domain): | ||
test_domain.register(User) | ||
test_domain.register(UserApplicationServices, part_of=User) | ||
test_domain.register(Registered, part_of=User) | ||
test_domain.init(traverse=False) | ||
|
||
mock_parent = mock.Mock() | ||
|
||
mock_parent.attach_mock(mock_enter, "m1") | ||
mock_parent.attach_mock(mock_exit, "m2") | ||
|
||
app_services_obj = UserApplicationServices() | ||
app_services_obj.register_user(email="[email protected]", name="John Doe") | ||
|
||
mock_parent.assert_has_calls( | ||
[ | ||
mock.call.m1(), | ||
mock.call.m2(None, None, None), | ||
] | ||
) |