Skip to content

Commit 0073ccc

Browse files
committed
fix tests
1 parent a020eeb commit 0073ccc

12 files changed

Lines changed: 118 additions & 105 deletions

File tree

src/modules/bidding/domain/entities.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
from dataclasses import dataclass, field
2-
from datetime import date, datetime, timedelta
2+
from datetime import datetime, timedelta
33
from typing import List, Optional
4-
from collections.abc import Sequence
54
from modules.bidding.domain.value_objects import Bid, Bidder, Seller
65
from modules.bidding.domain.rules import (
76
PlacedBidMustBeGreaterThanCurrentWinningBid,
87
BidCanBeRetracted,
98
ListingCanBeCancelled,
109
)
1110
from seedwork.domain.entities import AggregateRoot
12-
from seedwork.domain.events import DomainEvent
1311
from seedwork.domain.exceptions import DomainException
1412
from seedwork.domain.events import DomainEvent
15-
from seedwork.domain.value_objects import UUID, Money
13+
from seedwork.domain.value_objects import Money
1614

1715

1816
class BidderIsNotBiddingListing(DomainException):
@@ -51,7 +49,7 @@ def __post_init__(self) -> None:
5149
self.current_price = self.initial_price
5250

5351
# public commands
54-
def place_bid(self, bid: Bid) -> Sequence[DomainEvent]:
52+
def place_bid(self, bid: Bid) -> List[DomainEvent]:
5553
"""Public method"""
5654
self.check_rule(
5755
PlacedBidMustBeGreaterThanCurrentWinningBid(
@@ -66,7 +64,7 @@ def place_bid(self, bid: Bid) -> Sequence[DomainEvent]:
6664

6765
return [BidPlacedEvent(listing_id=self.id, bidder=bid.bidder, price=bid.price)]
6866

69-
def retract_bid_of(self, bidder: Bidder) -> Sequence[DomainEvent]:
67+
def retract_bid_of(self, bidder: Bidder) -> List[DomainEvent]:
7068
"""Public method"""
7169
bid = self.get_bid_of(bidder)
7270
self.check_rule(
@@ -76,7 +74,7 @@ def retract_bid_of(self, bidder: Bidder) -> Sequence[DomainEvent]:
7674
self._remove_bid_of(bidder=bidder)
7775
return [BidRetractedEvent(listing_id=self.id, bidder_id=bidder.uuid)]
7876

79-
def cancel_listing(self) -> Sequence[DomainEvent]:
77+
def cancel_listing(self) -> List[DomainEvent]:
8078
self.check_rule(
8179
ListingCanBeCancelled(
8280
time_left_in_listing=self.time_left_in_listing,
@@ -86,7 +84,7 @@ def cancel_listing(self) -> Sequence[DomainEvent]:
8684
self.ends_at = datetime.utcnow()
8785
return [ListingCancelledEvent(listing_id=self.id)]
8886

89-
def end_bidding(self) -> Sequence[DomainEvent]:
87+
def end_bidding(self) -> List[DomainEvent]:
9088
raise NotImplementedError()
9189
return []
9290

src/modules/catalog/application/command/create_listing_draft.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from seedwork.application.command_handlers import CommandResult
44
from seedwork.application.decorators import command_handler
55
from modules.catalog.domain.entities import Listing
6+
from modules.catalog.domain.events import ListingDraftCreatedEvent
67
from modules.catalog.domain.repositories import ListingRepository
78

89

@@ -19,10 +20,6 @@ class CreateListingDraftCommand(Command):
1920
def create_listing_draft(
2021
command: CreateListingDraftCommand, repository: ListingRepository
2122
) -> CommandResult:
22-
listing = Listing(id=repository.next_id(), **command.dict())
23-
try:
24-
repository.insert(listing)
25-
except Exception as e:
26-
return CommandResult.failed(message="Failed to create listing", exception=e)
27-
28-
return CommandResult.ok(result=listing.id)
23+
listing = Listing(id=Listing.next_id(), **command.dict())
24+
repository.insert(listing)
25+
return CommandResult.ok(result=listing.id, events=[ListingDraftCreatedEvent(listing_id=listing.id)])

src/modules/catalog/application/command/publish_listing.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from seedwork.application.commands import Command
22
from seedwork.domain.value_objects import UUID
3-
from modules.catalog.domain.repositories import ListingRepository, SellerRepository
43
from seedwork.application.command_handlers import CommandResult
54
from seedwork.application.decorators import command_handler
5+
from modules.catalog.domain.entities import Listing, Seller
6+
from modules.catalog.domain.repositories import ListingRepository, SellerRepository
67

78

89
class PublishListingCommand(Command):
@@ -18,12 +19,12 @@ def publish_listing(
1819
listing_repository: ListingRepository,
1920
seller_repository: SellerRepository,
2021
):
21-
listing = listing_repository.get_by_id(command.listing_id)
22-
seller = seller_repository.get_by_id(command.seller_id)
22+
listing: Listing = listing_repository.get_by_id(command.listing_id)
23+
seller: Seller = seller_repository.get_by_id(command.seller_id)
2324

24-
seller.publish_listing(listing)
25+
events = seller.publish_listing(listing)
2526

2627
# TODO: for now we need to manually persist the changes, but it should be handled automatically using "Unit of Work"
2728
listing_repository.update(listing)
2829

29-
return CommandResult.ok()
30+
return CommandResult.ok(events=events)
Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from seedwork.application.commands import Command
2-
from seedwork.domain.value_objects import Money, UUID
3-
from modules.catalog.domain.repositories import ListingRepository
42
from seedwork.application.command_handlers import CommandResult
53
from seedwork.application.decorators import command_handler
4+
from seedwork.domain.value_objects import Money, UUID
5+
from modules.catalog.domain.entities import Listing
6+
from modules.catalog.domain.repositories import ListingRepository
67

78

89
class UpdateListingDraftCommand(Command):
@@ -19,13 +20,9 @@ class UpdateListingDraftCommand(Command):
1920
def update_listing_draft(
2021
command: UpdateListingDraftCommand, repository: ListingRepository
2122
) -> CommandResult:
22-
listing = repository.get_by_id(command.listing_id)
23-
listing.change_main_attributes(
23+
listing: Listing = repository.get_by_id(command.listing_id)
24+
events = listing.change_main_attributes(
2425
title=command.title, description=command.description, price=command.price
2526
)
26-
try:
27-
repository.update(listing)
28-
except:
29-
return CommandResult.error("Failed to update listing")
30-
31-
return CommandResult.ok()
27+
repository.update(listing)
28+
return CommandResult.ok(events=events)
Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,41 @@
11
from dataclasses import dataclass
2-
from datetime import date
3-
from typing import Any
4-
from seedwork.domain.entities import Entity
2+
from typing import List
3+
from seedwork.domain.entities import AggregateRoot
54
from seedwork.domain.value_objects import Money, UUID
5+
from modules.catalog.domain.events import ListingDraftUpdatedEvent, ListingPublishedEvent, DomainEvent
66
from modules.catalog.domain.rules import ListingPriceMustBeGreaterThanZero
77
from .value_objects import ListingStatus
88

99

10-
class Listing(Entity):
10+
@dataclass
11+
class Listing(AggregateRoot):
1112
title: str
1213
description: str
1314
price: Money
1415
seller_id: UUID
1516
status = ListingStatus.DRAFT
1617

17-
def change_main_attributes(self, title: str, description: str, price: Money):
18+
def change_main_attributes(self, title: str, description: str, price: Money) -> List[DomainEvent]:
1819
self.title = title
1920
self.description = description
2021
self.price = price
2122

22-
def publish(self):
23-
self.status = ListingStatus.PUBLISHED
23+
return [ListingDraftUpdatedEvent(listing_id=self.id)]
2424

25+
def publish(self) -> List[DomainEvent]:
26+
self.check_rule(ListingPriceMustBeGreaterThanZero(price=self.price))
27+
self.status = ListingStatus.PUBLISHED
28+
return [ListingPublishedEvent(listing_id=self.id)]
2529

26-
class Seller(Entity):
30+
@dataclass
31+
class Seller(AggregateRoot):
2732
id: UUID
2833
is_new: bool = True
2934
currently_published_listings_count: int = 0
3035

31-
def publish_listing(self, listing):
36+
def publish_listing(self, listing) -> List[DomainEvent]:
3237
self.check_rule(ListingPriceMustBeGreaterThanZero(price=listing.price))
3338
# self.check_rule(ListingMustBeInDraftState(listing.status))
3439
# self.check_rule(SellerMustBeEligibleForAddingNextListing(self))
35-
listing.publish()
40+
return listing.publish()
41+

src/modules/catalog/domain/events.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
from seedwork.domain.value_objects import UUID
44

55

6-
@dataclass
76
class ListingDraftCreatedEvent(DomainEvent):
87
listing_id: UUID
8+
9+
10+
class ListingDraftUpdatedEvent(DomainEvent):
11+
listing_id: UUID
12+
13+
14+
class ListingPublishedEvent(DomainEvent):
15+
listing_id: UUID

src/modules/catalog/infrastructure/test_listing_repository.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ def test_listing_repo_is_empty(db_session):
1414

1515

1616
def test_listing_persistence(db_session):
17-
original = Listing(title="red dragon", description="", price=1, seller_id=UUID.v4())
18-
repo = PostgresJsonListingRepository(db_session=db_session)
17+
original = Listing(id=Listing.next_id(), title="red dragon", description="", price=1, seller_id=UUID.v4())
18+
repository = PostgresJsonListingRepository(db_session=db_session)
1919

20-
repo.insert(original)
20+
repository.insert(original)
2121
db_session.commit()
2222

23-
persisted = repo.get_by_id(original.id)
23+
persisted = repository.get_by_id(original.id)
2424

2525
assert original == persisted

src/modules/catalog/tests/application/test_command_handlers.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,32 @@
1414
from modules.catalog.domain.entities import Listing, Seller
1515
from modules.catalog.domain.value_objects import ListingStatus
1616
from seedwork.infrastructure.repository import InMemoryRepository
17-
from seedwork.domain.value_objects import UUID
17+
from seedwork.domain.value_objects import UUID, Money
1818

1919

2020
def test_create_listing_draft():
2121
# arrange
2222
command = CreateListingDraftCommand(
23-
title="foo", description="bar", price=1, seller_id=UUID.v4()
23+
title="foo", description="bar", price=Money(1), seller_id=Seller.next_id()
2424
)
2525
repository = InMemoryRepository()
2626

2727
# act
2828
result = create_listing_draft(command, repository)
29-
29+
3030
# assert
31-
assert repository.get_by_id(result.id).title == "foo"
31+
assert repository.get_by_id(result.result).title == "foo"
3232
assert result.has_errors() is False
3333

3434

3535
def test_update_listing_draft():
3636
# arrange
3737
repository = InMemoryRepository()
3838
listing = Listing(
39+
id=Listing.next_id(),
3940
title="Tiny dragon",
4041
description="Tiny dragon for sale",
41-
price=1,
42+
price=Money(1),
4243
seller_id=UUID.v4(),
4344
)
4445
repository.insert(listing)
@@ -60,16 +61,16 @@ def test_update_listing_draft():
6061

6162
def test_publish_listing():
6263
# arrange
63-
seller_id = UUID.v4()
6464
seller_repository = InMemoryRepository()
65-
seller = Seller()
65+
seller = Seller(id=Seller.next_id())
6666
seller_repository.insert(seller)
6767

6868
listing_repository = InMemoryRepository()
6969
listing = Listing(
70+
id=Listing.next_id(),
7071
title="Tiny dragon",
7172
description="Tiny dragon for sale",
72-
price=1,
73+
price=Money(1),
7374
seller_id=seller.id,
7475
)
7576
listing_repository.insert(listing)
@@ -85,6 +86,8 @@ def test_publish_listing():
8586
listing_repository=listing_repository,
8687
seller_repository=seller_repository,
8788
)
89+
90+
print(result)
8891

8992
# assert
9093
assert result.is_ok()
@@ -93,16 +96,16 @@ def test_publish_listing():
9396

9497
def test_publish_listing_and_break_business_rule():
9598
# arrange
96-
seller_id = UUID.v4()
9799
seller_repository = InMemoryRepository()
98-
seller = Seller()
100+
seller = Seller(id=Seller.next_id())
99101
seller_repository.insert(seller)
100102

101103
listing_repository = InMemoryRepository()
102104
listing = Listing(
105+
id=Listing.next_id(),
103106
title="Tiny dragon",
104107
description="Tiny dragon for sale",
105-
price=0, # this will break the rule
108+
price=Money(0), # this will break the rule
106109
seller_id=seller.id,
107110
)
108111
listing_repository.insert(listing)

src/modules/catalog/tests/domain/test_entities.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import pytest
2+
from seedwork.domain.exceptions import BusinessRuleValidationException
3+
from seedwork.domain.value_objects import Money
24
from modules.catalog.domain.entities import Seller, Listing
35
from modules.catalog.domain.value_objects import ListingStatus
4-
from seedwork.domain.exceptions import BusinessRuleValidationException
56

67

78
def test_seller_publishes_listing_happy_path():
8-
seller = Seller()
9+
seller = Seller(id=Seller.next_id())
910
listing = Listing(
11+
id=Listing.next_id(),
1012
title="Tiny dragon",
1113
description="Tiny dragon for sale",
12-
price=1,
14+
price=Money(1),
1315
seller_id=seller.id,
1416
)
1517

@@ -19,11 +21,12 @@ def test_seller_publishes_listing_happy_path():
1921

2022

2123
def test_seller_fails_to_publish_listing_with_zero_price():
22-
seller = Seller()
24+
seller = Seller(id=Seller.next_id())
2325
listing = Listing(
26+
id=Listing.next_id(),
2427
title="Tiny dragon",
2528
description="Tiny dragon for sale",
26-
price=0,
29+
price=Money(0),
2730
seller_id=seller.id,
2831
)
2932

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
from seedwork.domain.value_objects import Money
12
from modules.catalog.domain.rules import ListingPriceMustBeGreaterThanZero
23

34

45
def test_AuctionItemPriceMustBeGreaterThanZero_rule():
5-
rule = ListingPriceMustBeGreaterThanZero(price=1)
6+
rule = ListingPriceMustBeGreaterThanZero(price=Money(1))
67
assert not rule.is_broken()
78

89

910
def test_AuctionItemPriceMustBeGreaterThanZero_rule_is_broken():
10-
rule = ListingPriceMustBeGreaterThanZero(price=0)
11+
rule = ListingPriceMustBeGreaterThanZero(price=Money(0))
1112
assert rule.is_broken()

0 commit comments

Comments
 (0)