-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement Order Domain Objects - Cart, CartItem, CartItemOption (#1)
- Loading branch information
1 parent
749a3c2
commit 5407cc4
Showing
4 changed files
with
228 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
namespace AUSG.Eats.Order.Domain; | ||
|
||
public class Cart | ||
{ | ||
public long UserId { get; set; } | ||
|
||
// IList에는 AsReadOnly();가 없다. (why?) | ||
private readonly List<CartItem> _items = new List<CartItem>(); | ||
|
||
// IReadOnlyCollection에서 hint로 IEnumerable로 변경함 | ||
// hint로 Expression Body로 변경함 | ||
public IEnumerable<CartItem> Items => this._items.AsReadOnly(); | ||
|
||
public void AddToCart(CartItem newItem) | ||
{ | ||
this._items.Add(newItem); | ||
} | ||
|
||
public void RemoveFromCart(CartItem itemToRemove) | ||
{ | ||
this._items.Remove(itemToRemove); | ||
} | ||
|
||
public void AlterCartItem(CartItem itemToChange) | ||
{ | ||
if (!this._items.Remove(itemToChange)) // Id 비교이므로 제거된다. | ||
throw new ArgumentException("없는 CartItem을 변경하려고 한다."); | ||
this._items.Add(itemToChange); | ||
} | ||
|
||
public override bool Equals(object? obj) | ||
{ | ||
if ((obj == null) || !(this.GetType() == obj.GetType())) | ||
return false; | ||
var another = (Cart) obj; | ||
return this.UserId == another.UserId; | ||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
// Non-readonly property referenced in 'GetHashCode()' ?? | ||
return this.UserId.GetHashCode(); | ||
} | ||
} |
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,28 @@ | ||
namespace AUSG.Eats.Order.Domain; | ||
|
||
public class CartItem | ||
{ | ||
public long Id { get; set; } | ||
public List<CartItemOption> Options { get; set; } | ||
public int Quantity { get; set; } | ||
|
||
public CartItem(List<CartItemOption> options, int quantity) | ||
{ | ||
this.Options = options; | ||
this.Quantity = quantity; | ||
} | ||
|
||
public override bool Equals(object? obj) | ||
{ | ||
if ((obj == null) || !(this.GetType() == obj.GetType())) | ||
return false; | ||
var another = (CartItem) obj; | ||
return this.Id == another.Id; | ||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
// Non-readonly property referenced in 'GetHashCode()' ?? | ||
return this.Id.GetHashCode(); | ||
} | ||
} |
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,13 @@ | ||
namespace AUSG.Eats.Order.Domain; | ||
|
||
public class CartItemOption | ||
{ | ||
public string Name { get; } | ||
public decimal Price { get; } | ||
|
||
public CartItemOption(string name, decimal price) | ||
{ | ||
this.Name = name; | ||
this.Price = price; | ||
} | ||
} |
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,143 @@ | ||
using System.Collections.ObjectModel; | ||
using AUSG.Eats.Order.Domain; | ||
using Xunit; | ||
|
||
namespace AUSG.Eats.Order.Test; | ||
|
||
public class OrderTests | ||
{ | ||
|
||
private CartItem MakeNewCartItem() | ||
{ | ||
var options = new List<CartItemOption>(); | ||
const int quantity = 1; | ||
return new CartItem(options, quantity); | ||
} | ||
|
||
[Fact(DisplayName = "CartItemOption 객체는 Name과 Price 필드를 노출한다.")] | ||
public void CartItemOption_Shares_Name_and_Price() | ||
{ | ||
const string name = "name"; | ||
const decimal price = 1000m; | ||
var cartItemOption = new CartItemOption(name, price); | ||
|
||
Assert.Equal(cartItemOption.Name, name); | ||
Assert.Equal(cartItemOption.Price, price); | ||
} | ||
|
||
[Fact(DisplayName = "CartItem 객체는 Id, List<CarItemOption>, Quantity 필드를 노출한다.")] | ||
public void CartItem_Shares_Id_and_ListOfCartItemOption_and_Quantity() | ||
{ | ||
const long pid = 1L; | ||
var options = new List<CartItemOption>(); | ||
const int quantity = 0; | ||
var cartItem = new CartItem(options, quantity); | ||
cartItem.Id = pid; | ||
|
||
Assert.Equal(cartItem.Options, options); // IEnumerable ? | ||
Assert.Equal(cartItem.Quantity, quantity); | ||
Assert.Equal(cartItem.Id, pid); | ||
} | ||
|
||
[Fact(DisplayName = "Cart 객체는 List<CartItem> 필드를 노출한다.")] | ||
public void Cart_Shares_ListOfCartItem() | ||
{ | ||
var cart = new Cart(); | ||
Assert.Empty(cart.Items); // Collection && size=0 | ||
} | ||
|
||
[Fact(DisplayName = "Cart 객체가 노출하는 List<CartItem>은 외부에서 그 내용을 수정할 수 없어야 한다.")] | ||
public void ListOfCartItem_of_Cart_Must_Not_Be_Mutable() | ||
{ | ||
var cart = new Cart(); | ||
|
||
Assert.True(cart.Items is ReadOnlyCollection<CartItem>); | ||
} | ||
|
||
[Fact(DisplayName = "Cart 객체는 UserId 필드를 노출하며 UserId로 식별할 수 있다.")] | ||
public void Cart_Shares_UserId_and_Can_be_Identified_Using_UserId() | ||
{ | ||
var cart1 = new Cart(); | ||
var cart2 = new Cart(); | ||
var userId = 1L; | ||
cart1.UserId = userId; | ||
cart2.UserId = userId; | ||
|
||
// Shares Id | ||
Assert.Equal(cart1.UserId, userId); | ||
|
||
// Identified by UserId | ||
Assert.Equal(cart1, cart2); | ||
|
||
// Compare HashCode | ||
Assert.Equal(cart1.GetHashCode(), cart2.GetHashCode()); | ||
} | ||
|
||
[Fact(DisplayName = "Cart 객체는 CartItem을 추가할 수 있다.")] | ||
public void Cart_can_Add_CartItem() | ||
{ | ||
var cart = new Cart(); | ||
var cartItem1 = MakeNewCartItem(); | ||
cart.AddToCart(cartItem1); | ||
|
||
Assert.Equal(cart.Items.ElementAt(0), cartItem1); | ||
} | ||
|
||
[Fact(DisplayName = "Cart 객체는 CartItem을 제거할 수 있다.")] | ||
public void Cart_can_Remove_CartItem() | ||
{ | ||
// given | ||
var cart = new Cart(); | ||
var cartItem1 = MakeNewCartItem(); | ||
cart.AddToCart(cartItem1); | ||
Assert.Equal(cart.Items.ElementAt(0), cartItem1); | ||
|
||
// when | ||
cart.RemoveFromCart(cartItem1); | ||
|
||
// then | ||
Assert.Empty(cart.Items); | ||
} | ||
|
||
[Fact(DisplayName = "Cart 객체는 CartItem을 변경할 수 있다.")] | ||
public void Cart_can_Alter_CartItem() | ||
{ | ||
// given | ||
const long cartItemId = 1L; | ||
var cart = new Cart(); | ||
var oldItem = MakeNewCartItem(); | ||
oldItem.Id = cartItemId; | ||
cart.AddToCart(oldItem); | ||
|
||
// when (Item의 상태를 변경함) | ||
// 가능한 모든 필드가 변경됨을 확인하는 게 적절할 것으로 보임 | ||
var newOptions = new List<CartItemOption>(); | ||
const int newQuantity = 2; | ||
oldItem.Options = newOptions; | ||
oldItem.Quantity = newQuantity; | ||
cart.AlterCartItem(oldItem); | ||
|
||
// then | ||
var alteredItem = cart.Items.ElementAt(0); | ||
Assert.Equal(alteredItem.Id, oldItem.Id); | ||
Assert.Equal(alteredItem.Options, newOptions); // Collection의 새 레퍼런스의 일치 확인해도 충분하다. | ||
Assert.Equal(alteredItem.Quantity, newQuantity); | ||
} | ||
|
||
// 추가 TC | ||
[Fact(DisplayName = "Cart 객체는 CartItem을 변경할 때 해당 Item이 이미 List에 없다면 예외를 발생시킨다.")] | ||
public void Cart_throw_ArgumentException_when_Alter_CartItem() | ||
{ | ||
// given | ||
var cart = new Cart(); | ||
var oldItem = MakeNewCartItem(); | ||
oldItem.Id = 1L; | ||
|
||
// when (Item의 상태를 변경함) | ||
// 가능한 모든 필드가 변경됨을 확인하는 게 적절할 것으로 보임 | ||
Action alterItem = () => cart.AlterCartItem(oldItem); | ||
|
||
// then | ||
ArgumentException ex = Assert.Throws<ArgumentException>(alterItem); | ||
} | ||
} |