Skip to content
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

[BE] 27.07 주식 주문 서비스 테스트 코드 작성 #237 #245

Merged
merged 4 commits into from
Dec 3, 2024
Merged
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
251 changes: 251 additions & 0 deletions BE/src/stock/order/stock-order.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
import { Test } from '@nestjs/testing';
import {
BadRequestException,
ConflictException,
ForbiddenException,
} from '@nestjs/common';
import { StockOrderService } from './stock-order.service';
import { StockOrderRepository } from './stock-order.repository';
import { StockPriceSocketService } from '../../stockSocket/stock-price-socket.service';
import { UserStockRepository } from '../../asset/user-stock.repository';
import { AssetRepository } from '../../asset/asset.repository';
import { TradeType } from './enum/trade-type';
import { StatusType } from './enum/status-type';

describe('stock order test', () => {
let stockOrderService: StockOrderService;
let stockOrderRepository: StockOrderRepository;
let assetRepository: AssetRepository;
let userStockRepository: UserStockRepository;

beforeEach(async () => {
const mockStockOrderRepository = {
findBy: jest.fn(),
save: jest.fn(),
create: jest.fn(),
findOneBy: jest.fn(),
remove: jest.fn(),
existsBy: jest.fn(),
};
const mockAssetRepository = { findOneBy: jest.fn() };
const mockStockPriceSocketService = {
subscribeByCode: jest.fn(),
unsubscribeByCode: jest.fn(),
};
const mockUserStockRepository = { findOneBy: jest.fn() };

const module = await Test.createTestingModule({
providers: [
StockOrderService,
{ provide: StockOrderRepository, useValue: mockStockOrderRepository },
{ provide: AssetRepository, useValue: mockAssetRepository },
{
provide: StockPriceSocketService,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 이런 식으로만 하면 되나요?!?!! 저 실시간 체결가 api 테스트 코드 짜는데 자꾸 이런.. 사용하지도 않을 의존성 때문에 에러 뜨고 추가하면 추가한대로 에러 뜨고 해서 진행을 못하고 있었거든요 ㅠㅠㅠㅠ 참고해서 해보겠습니다

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

마자요...... 의존성 타고타고 계속 추가해야되더라구요ㅋㅋㅋ 일단 이렇게 하니까 그 문제는 해결되긴 했어요! 대신 서비스에서 사용하는 메소드들은 mockRepository 같은거 만들때 귀찮지만 아래처럼 선언해줘야 되더라구용

    const mockStockOrderRepository = {
      findBy: jest.fn(),
      save: jest.fn(),
      create: jest.fn(),
      findOneBy: jest.fn(),
      remove: jest.fn(),
      existsBy: jest.fn(),
    };

useValue: mockStockPriceSocketService,
},
{ provide: UserStockRepository, useValue: mockUserStockRepository },
],
}).compile();

stockOrderService = module.get(StockOrderService);
stockOrderRepository = module.get(StockOrderRepository);
assetRepository = module.get(AssetRepository);
userStockRepository = module.get(UserStockRepository);
});

it('충분한 자산을 가지고 특정 주식에 대해 매수를 요청할 경우, 요청이 DB에 정상적으로 등록된다.', async () => {
jest.spyOn(assetRepository, 'findOneBy').mockResolvedValue({
id: 1,
user_id: 1,
stock_balance: 0,
cash_balance: 1000,
total_asset: 1000,
total_profit: 0,
total_profit_rate: 0,
});

jest.spyOn(stockOrderRepository, 'findBy').mockResolvedValue([]);

const createMock = jest.fn();
jest.spyOn(stockOrderRepository, 'create').mockImplementation(createMock);

const saveMock = jest.fn();
jest.spyOn(stockOrderRepository, 'save').mockImplementation(saveMock);

await stockOrderService.buy(1, {
stock_code: '005930',
price: 1000,
amount: 1,
});

expect(createMock).toHaveBeenCalledWith({
user_id: 1,
stock_code: '005930',
trade_type: TradeType.BUY,
amount: 1,
price: 1000,
status: StatusType.PENDING,
});
expect(saveMock).toHaveBeenCalled();
});

it('자산이 부족한 상태로 특정 주식에 대해 매수를 요청할 경우, BadRequest 예외가 발생한다.', async () => {
jest.spyOn(assetRepository, 'findOneBy').mockResolvedValue({
id: 1,
user_id: 1,
stock_balance: 0,
cash_balance: 1000,
total_asset: 1000,
total_profit: 0,
total_profit_rate: 0,
});

jest.spyOn(stockOrderRepository, 'findBy').mockResolvedValue([
{
id: 1,
user_id: 1,
stock_code: '005930',
trade_type: TradeType.BUY,
amount: 1,
price: 1000,
status: StatusType.PENDING,
created_at: new Date(),
},
]);

await expect(
stockOrderService.buy(1, {
stock_code: '005930',
price: 1000,
amount: 1,
}),
).rejects.toThrow(BadRequestException);
});

it('충분한 주식을 가지고 특정 주식에 대해 매도를 요청할 경우, 요청이 DB에 정상적으로 등록된다.', async () => {
jest.spyOn(userStockRepository, 'findOneBy').mockResolvedValue({
id: 1,
user_id: 1,
stock_code: '005930',
quantity: 1,
avg_price: 1000,
last_updated: new Date(),
});

jest.spyOn(stockOrderRepository, 'findBy').mockResolvedValue([]);

const createMock = jest.fn();
jest.spyOn(stockOrderRepository, 'create').mockImplementation(createMock);

const saveMock = jest.fn();
jest.spyOn(stockOrderRepository, 'save').mockImplementation(saveMock);

await stockOrderService.sell(1, {
stock_code: '005930',
price: 1000,
amount: 1,
});

expect(createMock).toHaveBeenCalledWith({
user_id: 1,
stock_code: '005930',
trade_type: TradeType.SELL,
amount: 1,
price: 1000,
status: StatusType.PENDING,
});
expect(saveMock).toHaveBeenCalled();
});

it('주식이 부족한 상태로 특정 주식에 대해 매도를 요청할 경우, BadRequest 예외가 발생한다.', async () => {
jest.spyOn(userStockRepository, 'findOneBy').mockResolvedValue({
id: 1,
user_id: 1,
stock_code: '005930',
quantity: 1,
avg_price: 1000,
last_updated: new Date(),
});

jest.spyOn(stockOrderRepository, 'findBy').mockResolvedValue([
{
id: 1,
user_id: 1,
stock_code: '005930',
trade_type: TradeType.SELL,
amount: 1,
price: 1000,
status: StatusType.PENDING,
created_at: new Date(),
},
]);

await expect(
stockOrderService.sell(1, {
stock_code: '005930',
price: 1000,
amount: 1,
}),
).rejects.toThrow(BadRequestException);
});

it('사용자 본인의 미체결된 주문에 대해 취소를 요청할 경우, 해당 주문이 DB에서 삭제된다.', async () => {
jest.spyOn(stockOrderRepository, 'findOneBy').mockResolvedValue({
id: 1,
user_id: 1,
stock_code: '005930',
trade_type: TradeType.SELL,
amount: 1,
price: 1000,
status: StatusType.PENDING,
created_at: new Date(),
});

const removeMock = jest.fn();
jest.spyOn(stockOrderRepository, 'remove').mockImplementation(removeMock);

await stockOrderService.cancel(1, 1);

expect(removeMock).toHaveBeenCalled();
});

it('사용자 본인의 주문이 아닌 주문에 대해 취소를 요청할 경우, Forbidden 예외가 발생한다.', async () => {
jest.spyOn(stockOrderRepository, 'findOneBy').mockResolvedValue({
id: 1,
user_id: 2,
stock_code: '005930',
trade_type: TradeType.SELL,
amount: 1,
price: 1000,
status: StatusType.PENDING,
created_at: new Date(),
});

const removeMock = jest.fn();
jest.spyOn(stockOrderRepository, 'remove').mockImplementation(removeMock);

await expect(stockOrderService.cancel(1, 1)).rejects.toThrow(
ForbiddenException,
);
});

it('이미 체결된 주문에 대해 취소를 요청할 경우, Conflict 예외가 발생한다.', async () => {
jest.spyOn(stockOrderRepository, 'findOneBy').mockResolvedValue({
id: 1,
user_id: 1,
stock_code: '005930',
trade_type: TradeType.SELL,
amount: 1,
price: 1000,
status: StatusType.COMPLETE,
created_at: new Date(),
});

const removeMock = jest.fn();
jest.spyOn(stockOrderRepository, 'remove').mockImplementation(removeMock);

await expect(stockOrderService.cancel(1, 1)).rejects.toThrow(
ConflictException,
);
});
});
Loading