Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 자동차 경주 미션
# 로또 미션

## 참고링크 및 저장소

Expand Down
129 changes: 129 additions & 0 deletions src/__tests__/lotto.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import Lotto from '../domain/Lotto.js';
import { lottoValidations } from '../validations/lotto.js';
import LOTTO_TYPE from '../constants/lottoType.js';

describe('로또 테스트', () => {
test('로또 번호는 [당첨, 티켓] 두가지 유형을 가질 수 있다.', () => {
expect(
() =>
new Lotto({
type: 'otherType',
numbers: [1, 2, 3, 4, 5, 6],
}),
).toThrow(lottoValidations.lottoType.errorMessage);
});

test('로또 번호는 6개여야 한다.', () => {
expect(
() =>
new Lotto({
type: LOTTO_TYPE.TICKET,
numbers: [1, 2, 3, 4, 5],
}),
).toThrow(lottoValidations.lottoNumbersLength.errorMessage);
});

test('당첨 로또 번호는 보너스 번호를 가져야 한다.', () => {
expect(
() =>
new Lotto({
type: LOTTO_TYPE.WINNING,
numbers: [1, 2, 3, 4, 5, 6],
}),
).toThrow(lottoValidations.winningLottoHasBonus.errorMessage);
});

test('티켓 로또 번호는 보너스 번호가 없어야 한다.', () => {
expect(
() =>
new Lotto({
type: LOTTO_TYPE.TICKET,
numbers: [1, 2, 3, 4, 5, 6],
bonusNumber: 7,
}),
).toThrow(lottoValidations.ticketLottoBonusNull.errorMessage);
});

test('로또 번호는 각각 달라야 한다.', () => {
expect(
() =>
new Lotto({
type: LOTTO_TYPE.WINNING,
numbers: [1, 2, 3, 4, 5, 6],
bonusNumber: 6,
}),
).toThrow(lottoValidations.lottoEachUnique.errorMessage);

expect(
() =>
new Lotto({
type: LOTTO_TYPE.TICKET,
numbers: [1, 2, 3, 3, 5, 6],
}),
).toThrow(lottoValidations.lottoEachUnique.errorMessage);
});

test('모든 로또 번호는 정수여야 한다.', () => {
expect(
() =>
new Lotto({
type: LOTTO_TYPE.TICKET,
numbers: [1, 2, 3, 4, 5, '6'],
}),
).toThrow(lottoValidations.lottoInteger.errorMessage);
});

test('모든 로또 번호는 1 이상 45 이하여야 한다.', () => {
expect(
() =>
new Lotto({
type: LOTTO_TYPE.WINNING,
numbers: [1, 2, 3, 4, 5, 45],
bonusNumber: 46,
}),
).toThrow(lottoValidations.lottoRange.errorMessage);

expect(
() =>
new Lotto({
type: LOTTO_TYPE.TICKET,
numbers: [0, 1, 2, 3, 4, 5],
}),
).toThrow(lottoValidations.lottoRange.errorMessage);
});

test('숫자 리스트를 통해 로또 티켓을 생성할 수 있다.', () => {
expect(new Lotto([1, 2, 3, 4, 5, 6]).numbers).toEqual([1, 2, 3, 4, 5, 6]);
});

test('로또에서 특정 번호가 포함되어있는지 여부를 알 수 있다.', () => {
const lotto1 = new Lotto([1, 2, 3, 4, 5, 6]);
const lotto2 = new Lotto({
type: LOTTO_TYPE.WINNING,
numbers: [1, 2, 3, 4, 5, 6],
bonusNumber: 7,
});

expect(lotto1.contain(7)).toBe(false);
expect(lotto2.contain(7)).toBe(true);
});

test('유효한 로또로만 로또를 비교할 수 있다.', () => {
const lotto1 = new Lotto([1, 2, 3, 4, 5, 6]);
const lotto2 = [1, 2, 3, 4, 5, 6];

expect(() => lotto1.matchNumbers(lotto2)).toThrow(lottoValidations.lottoInstance.errorMessage);
});

test('두 로또를 비교하여 겹치는 숫자 목록을 확인할 수 있다.', () => {
const lotto1 = new Lotto([1, 2, 3, 4, 5, 6]);
const lotto2 = new Lotto({
type: LOTTO_TYPE.WINNING,
numbers: [3, 4, 5, 6, 7, 8],
bonusNumber: 2,
});

expect(lotto1.matchNumbers(lotto2)).toEqual([3, 4, 5, 6]);
expect(lotto2.matchNumbers(lotto1)).toEqual([3, 4, 5, 6]);
});
});
21 changes: 21 additions & 0 deletions src/__tests__/lottoPayment.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import LottoPayment from '../domain/LottoPayment.js';
import { lottoPaymentValidations } from '../validations/lottoPayment.js';

describe('로또 결제 테스트', () => {
test('로또 결제 금액은 정수여야 한다.', () => {
expect(() =>
LottoPayment.createLottoTickets({
payAmount: '1000',
}),
).toThrow(lottoPaymentValidations.payAmountInteger.errorMessage);
});

test('로또 결제는 1000원 단위로만 가능하다.', () => {
expect(() => LottoPayment.createLottoTickets(1100)).toThrow(lottoPaymentValidations.payAmountUnit1000.errorMessage);
});

test('1000원 당 1장의 로또 티켓을 발행해야 한다.', () => {
const lottoTickets = LottoPayment.createLottoTickets(8000);
expect(lottoTickets.length).toBe(8);
});
});
160 changes: 160 additions & 0 deletions src/__tests__/lottoRuleSet.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import LottoRuleSet from '../domain/LottoRuleSet.js';
import { lottoRuleSetValidations } from '../validations/lottoRuleSet.js';

vi.mock('../domain/createLottoNumbers');

describe('로또 규칙 테스트', async () => {
test('로또 규칙은 순위가 1위부터 최하위까지 올바르게 매겨져야 한다.', () => {
const rankingRuleHasInvalidRank1 = [
{
matchCount: 3,
bonusMatch: false,
profit: 1000,
rank: -1,
distribute: 0.5,
},
];
expect(
() =>
new LottoRuleSet({
initialRule: rankingRuleHasInvalidRank1,
}),
).toThrow(lottoRuleSetValidations.validRanks.errorMessage);

const rankingRuleHasInvalidRank2 = [
{
matchCount: 3,
bonusMatch: false,
profit: 1000,
rank: 3,
distribute: 0.5,
},
];
expect(
() =>
new LottoRuleSet({
initialRule: rankingRuleHasInvalidRank2,
}),
).toThrow(lottoRuleSetValidations.hasAllRanks.errorMessage);
});

test('로또 규칙에서 각 순위의 distribute 의 합은 1을 넘으면 안된다.', () => {
const rankingRuleHasInvalidDistributeSum = [
{
bonusMatch: true,
profit: 1000,
rank: 1,
matchCount: 3,
distribute: 0.5,
},
{
bonusMatch: true,
profit: 1000,
rank: 2,
matchCount: 2,
distribute: 0.4,
},
{
bonusMatch: true,
profit: 1000,
rank: 3,
matchCount: 1,
distribute: 0.3,
},
];
expect(() => new LottoRuleSet({ initialRule: rankingRuleHasInvalidDistributeSum })).toThrow(
lottoRuleSetValidations.distributeSum.errorMessage,
);
});

test('로또 규칙에는 유효한 matchCount, bonus, profit, distribute 이 포함되어야 한다.', () => {
const rankingRuleHasInvalidMatchCount = [
{
bonusMatch: true,
profit: 1000,
rank: 1,
matchCount: 100,
distribute: 0.5,
},
];
expect(
() =>
new LottoRuleSet({
initialRule: rankingRuleHasInvalidMatchCount,
}),
).toThrow(lottoRuleSetValidations.validMatchCounts.errorMessage);

const rankingRuleHasInvalidBonusMatch = [
{
profit: 1000,
rank: 1,
matchCount: 3,
bonusMatch: 'false',
},
];
expect(
() =>
new LottoRuleSet({
initialRule: rankingRuleHasInvalidBonusMatch,
}),
).toThrow(lottoRuleSetValidations.validBonusMatches.errorMessage);

const rankingRuleHasInvalidProfit = [
{
bonusMatch: true,
profit: '1000',
rank: 1,
matchCount: 3,
distribute: 0.5,
},
];
expect(
() =>
new LottoRuleSet({
initialRule: rankingRuleHasInvalidProfit,
}),
).toThrow(lottoRuleSetValidations.validProfits.errorMessage);

const rankingRuleHasInvalidDistribute = [
{
bonusMatch: true,
profit: 1000,
rank: 1,
matchCount: 3,
distribute: -1,
},
];
expect(
() =>
new LottoRuleSet({
initialRule: rankingRuleHasInvalidDistribute,
}),
).toThrow(lottoRuleSetValidations.validDistribute.errorMessage);
});

test('increaseRankProfit은 남은 액수와 distribute 비율을 기반으로 각 순위의 profit을 증가시켜야 한다.', () => {
const initialRule = [
{
matchCount: 5,
bonusMatch: true,
profit: 1000,
rank: 1,
distribute: 0.6,
},
{
matchCount: 5,
bonusMatch: false,
profit: 600,
rank: 2,
distribute: 0.4,
},
];
const lottoRuleSet = new LottoRuleSet({ initialRule: initialRule });

lottoRuleSet.increaseRankProfit(1000);
const updatedRules = lottoRuleSet.rules;

expect(updatedRules.find(({ rank }) => rank === 1).profit).toBe(1600);
expect(updatedRules.find(({ rank }) => rank === 2).profit).toBe(1000);
});
});
69 changes: 69 additions & 0 deletions src/__tests__/lottoSystem.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import LottoSystem from '../domain/LottoSystem.js';
import createLottoNumbers from '../domain/createLottoNumbers.js';
import Lotto from '../domain/Lotto.js';

vi.mock('../domain/createLottoNumbers');

describe('로또 시스템 테스트', async () => {
const originalCreateLottoNumbers = await vi
.importActual('../domain/createLottoNumbers')
.then((module) => module.default);

beforeEach(() => {
createLottoNumbers.mockReset();
createLottoNumbers.mockImplementation(originalCreateLottoNumbers);
});

test('로또 시스템은 정확한 개수의 로또를 구매한다.', () => {
const lottoSystem = new LottoSystem();
lottoSystem.payLottoTicket(10000);

expect(lottoSystem.ticketCount).toBe(10);
expect(lottoSystem.paidAmount).toBe(10000);
});

test('로또 시스템에서 로또 티켓의 등수를 확인할 수 있다.', () => {
const lottoSystem = new LottoSystem();
lottoSystem.setWinningLotto([1, 2, 3, 4, 5, 6], 7);

expect(lottoSystem.getRank(new Lotto([1, 2, 3, 4, 5, 6]))).toBe(1);
expect(lottoSystem.getRank(new Lotto([1, 2, 3, 4, 5, 7]))).toBe(2);
expect(lottoSystem.getRank(new Lotto([1, 2, 3, 4, 5, 8]))).toBe(3);
expect(lottoSystem.getRank(new Lotto([1, 2, 3, 4, 7, 8]))).toBe(4);
expect(lottoSystem.getRank(new Lotto([1, 2, 3, 7, 8, 9]))).toBe(5);
});

test('로또 시스템은 총 수익을 계산할 수 있다.', () => {
createLottoNumbers
.mockReturnValueOnce([1, 2, 3, 4, 5, 6]) // 1등
.mockReturnValueOnce([1, 2, 3, 4, 15, 16]); // 4등

const lottoSystem = new LottoSystem();
lottoSystem.setWinningLotto([1, 2, 3, 4, 5, 6], 7);
lottoSystem.payLottoTicket(2000);

expect(lottoSystem.profitAmount).toBe(2000050000);
});

test('로또 시스템은 당첨금이 지불된 후의 남은 구매금액을 계산할 수 있다.', () => {
createLottoNumbers.mockReturnValueOnce([1, 2, 3, 4, 5, 6]).mockReturnValue([7, 8, 9, 10, 11, 12]);

const lottoSystem = new LottoSystem();
lottoSystem.setWinningLotto([4, 5, 6, 13, 14, 15], 16);
lottoSystem.payLottoTicket(100000);

expect(lottoSystem.leftPaidAmount).toBe(95000);
});

test('로또 시스템은 수익율을 계산할 수 있다.', () => {
createLottoNumbers
.mockReturnValueOnce([1, 2, 3, 4, 15, 16]) // 4등 = 50000
.mockImplementation(() => [11, 12, 13, 14, 15, 16]);

const lottoSystem = new LottoSystem();
lottoSystem.setWinningLotto([1, 2, 3, 4, 5, 6], 7);
lottoSystem.payLottoTicket(100000);

expect(lottoSystem.profitRatio).toBe(50);
});
});
Loading