Skip to content

8장 실습 코드입니다. #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hamo-o/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
16 changes: 16 additions & 0 deletions hamo-o/chap8/Customer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Customer } from "./after";

describe("Customer 클래스 테스트", () => {
test("Customer 생성자: 이름과 프리미엄 여부가 설정되는지 확인", () => {
const customer = new Customer("Jane Doe", true);
expect(customer.name).toBe("Jane Doe");
expect(customer.isPremium).toBe(true);
expect(customer.discountRate).toBe(0.1);
});

test("Customer 생성자: 기본 설정이 정확한지 확인", () => {
const customer = new Customer("John Smith", false);
expect(customer.name).toBe("John Smith");
expect(customer.isPremium).toBe(false);
});
});
65 changes: 65 additions & 0 deletions hamo-o/chap8/Order.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Order, OrderItem, Customer } from "./after";

describe("Order 클래스 테스트", () => {
let customer;
let order;
let item1;
let item2;

describe("일반 고객", () => {
beforeEach(() => {
customer = new Customer("John Doe", false); // 일반 고객 생성
order = new Order(customer);
item1 = new OrderItem("Laptop", 1000, 100); // 테스트용 상품 1 생성
item2 = new OrderItem("Phone", 500, 5); // 테스트용 상품 2 생성
});

test("Order 생성자: 초기 값 설정", () => {
expect(order.customer).toBe(customer);
expect(order.items).toEqual([]);
});

test("addItem: 아이템을 추가하면 items 배열에 저장되는지 확인", () => {
order.addItem(item1, 2);
expect(order.items.length).toBe(1);
expect(order.items[0].item).toBe(item1);
expect(order.items[0].quantity).toBe(2);
});

test("calculateTotal: 총 금액 계산 (일반 고객)", () => {
order.addItem(item1, 1); // 1000 * 1 = 1000
order.addItem(item2, 1); // 500 * 1 = 500, 총 1500

const total = order.calculateTotal();
expect(total).toBe(1500 * 0.95 + 5000); // 할인율: 5%, 배송비: 5000
});

test("calculateTotal: 총 금액이 50000원 초과 시 무료 배송 적용", () => {
order.addItem(item1, 51); // 1000 * 51 = 51000
const total = order.calculateTotal();
expect(total).toBe(51000 * 0.95); // 할인율: 5%, 무료 배송
});

test("calculateTotal: 재고 부족 시 에러 발생", () => {
order.addItem(item2, 6); // item2의 재고는 5개, 6개 요청 시 에러 발생
expect(() => order.calculateTotal()).toThrow("재고가 부족합니다.");
});
});

describe("프리미엄 고객", () => {
beforeEach(() => {
customer = new Customer("John Doe", true); // 프리미엄 고객 생성
order = new Order(customer);
item1 = new OrderItem("Laptop", 1000, 100); // 테스트용 상품 1 생성
item2 = new OrderItem("Phone", 500, 5); // 테스트용 상품 2 생성
});

test("calculateTotal: 총 금액 계산 (프리미엄 고객)", () => {
order.addItem(item1, 1); // 1000 * 1 = 1000
order.addItem(item2, 1); // 500 * 1 = 500, 총 1500

const total = order.calculateTotal();
expect(total).toBe(1500 * 0.9 + 5000); // 할인율: 10%, 배송비: 5000
});
});
});
23 changes: 23 additions & 0 deletions hamo-o/chap8/OrderItem.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { OrderItem } from "./after";

describe("OrderItem 클래스 테스트", () => {
test("OrderItem 생성자: 이름, 가격, 재고가 설정되는지 확인", () => {
const item = new OrderItem("Tablet", 200, 15);
expect(item.name).toBe("Tablet");
expect(item.price).toBe(200);
expect(item.stock).toBe(15);
});

test("OrderItem 생성자: 값이 잘못 설정된 경우 초기 값이 올바른지 확인", () => {
const item = new OrderItem("Headphones", 150, 0);
expect(item.name).toBe("Headphones");
expect(item.price).toBe(150);
expect(item.stock).toBe(0);
});

test("calculateBasePrice: 가격 계산이 올바르게 수행되는지 확인", () => {
const item = new OrderItem("Laptop", 1000, 1);
const basePrice = item.calculateBasePrice(3);
expect(basePrice).toBe(3000);
});
});
69 changes: 69 additions & 0 deletions hamo-o/chap8/after.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
export class Order {
constructor(customer) {
this.customer = customer;
this.items = [];
}

addItem(item, quantity) {
this.items.push({ item, quantity });
}

calculateTotal() {
this.#validateStock();

const total = this.#calculateBaseTotalPrice();
const shippingCost = this.#calculateShippingCost(total);

return this.customer.discount(total) + shippingCost;
}

#calculateShippingCost(total) {
if (total > 50000) return 0;
return 5000;
}

#calculateBaseTotalPrice() {
return this.items.reduce(
(total, { item, quantity }) =>
(total += item.calculateBasePrice(quantity)),
0
);
}

#validateStock() {
this.items.forEach((item) => {
if (item.item.stock < item.quantity) {
throw new Error("재고가 부족합니다.");
}
});
}
}

export class Customer {
constructor(name, isPremium) {
this.name = name;
this.isPremium = isPremium;
this.discountRate = this.#calculateDiscountRate();
}

#calculateDiscountRate() {
if (this.isPremium) return 0.1;
return 0.05;
}

discount(price) {
return price * (1 - this.discountRate);
}
}

export class OrderItem {
constructor(name, price, stock) {
this.name = name;
this.price = price;
this.stock = stock;
}

calculateBasePrice(quantity) {
return quantity * this.price;
}
}
69 changes: 69 additions & 0 deletions hamo-o/chap8/before.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// 주문 처리 시스템 예제
export class Order {
constructor(customer) {
this.customer = customer;
this.items = [];
// 필드 옮기기 대상: discountRate는 Customer 클래스로 이동 가능
this.discountRate = 0;
}

// 함수 옮기기 대상: calculateBasePrice는 OrderItem 클래스로 이동 가능
calculateBasePrice(quantity, itemPrice) {
return quantity * itemPrice;
}

addItem(item, quantity) {
this.items.push({
item: item,
quantity: quantity,
});
}

// 문장을 함수로 옮기기 대상: 배송비 계산 로직을 별도 함수로 분리 가능
calculateTotal() {
let total = 0;

// 반복문 쪼개기 대상: 상품 가격 계산과 재고 확인을 별도의 반복문으로 분리 가능
for (const item of this.items) {
// 인라인 코드를 함수 호출로 바꾸기 대상: 재고 확인 로직을 함수로 추출 가능
if (item.item.stock < item.quantity) {
throw new Error("재고가 부족합니다.");
}
total += this.calculateBasePrice(item.quantity, item.item.price);
}

// 문장 슬라이드하기 대상: 할인율 계산 로직을 관련 코드 근처로 이동 가능
let shippingCost = 0;
if (total > 50000) {
shippingCost = 0;
} else {
shippingCost = 5000;
}

if (this.customer.isPremium) {
this.discountRate = 0.1;
} else {
this.discountRate = 0.05;
}

// 문장을 호출한 곳으로 옮기기 대상: 할인 적용 로직을 호출하는 쪽으로 이동 가능
total = total * (1 - this.discountRate);

return total + shippingCost;
}
}

export class Customer {
constructor(name, isPremium) {
this.name = name;
this.isPremium = isPremium;
}
}

export class OrderItem {
constructor(name, price, stock) {
this.name = name;
this.price = price;
this.stock = stock;
}
}
26 changes: 26 additions & 0 deletions hamo-o/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "hamo-o",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"test": "jest --detectOpenHandles"
},
"devDependencies": {
"@babel/core": "^7.25.8",
"@babel/preset-env": "^7.25.8",
"babel-jest": "^29.6.0",
"jest": "^29.6.0"
},
"jest": {
"transform": {
"\\.js$": "babel-jest"
}
},
"babel": {
"presets": [
"@babel/preset-env"
]
}
}
Loading