const { expect } = require('chai'); const sinon = require('sinon'); const proxyquire = require('proxyquire'); const fs = require('fs').promises; // models의 각 모델을 미리 stub const mockModels = { EventScore: { findAll: sinon.stub() }, Member: { findByPk: sinon.stub() }, Club: { findByPk: sinon.stub() } }; // proxyquire로 averageService를 models stub과 함께 불러오기 let averageService; // averageService를 require (이 시점에 models가 이미 stub됨) describe('averageService', () => { let sandbox; let freshAverageService; beforeEach(() => { sandbox = sinon.createSandbox(); mockModels.EventScore.findAll.reset(); mockModels.Member.findByPk.reset(); mockModels.Club.findByPk.reset(); freshAverageService = proxyquire.noCallThru().load('../../services/averageService', { '../models': mockModels }); }); afterEach(() => { sandbox.restore(); }); describe('calculateMemberAverage', () => { it('점수가 없을 경우 기본값 0을 반환해야 함', async () => { sandbox.stub(fs, 'mkdir').resolves(); sandbox.stub(fs, 'writeFile').resolves(); sandbox.stub(fs, 'readFile').rejects({ code: 'ENOENT' }); mockModels.EventScore.findAll.resolves([]); sandbox.stub(freshAverageService, 'getFromCache').resolves(null); sandbox.stub(freshAverageService, 'setToCache').resolves(true); sandbox.stub(freshAverageService, 'invalidateCache').resolves(true); const startDate = new Date('2023-01-01'); const endDate = new Date('2023-12-31'); const result = await freshAverageService.calculateMemberAverage(1, startDate, endDate); expect(result).to.deep.equal({ average: 0, games: 0, totalScore: 0 }); expect(mockModels.EventScore.findAll.called).to.be.true; }); it('점수가 있을 경우 올바른 평균을 계산해야 함', async () => { sandbox.stub(fs, 'mkdir').resolves(); sandbox.stub(fs, 'writeFile').resolves(); sandbox.stub(fs, 'readFile').rejects({ code: 'ENOENT' }); mockModels.EventScore.findAll.resolves([ { score: 180 }, { score: 200 }, { score: 220 } ]); sandbox.stub(freshAverageService, 'getFromCache').resolves(null); sandbox.stub(freshAverageService, 'setToCache').resolves(true); sandbox.stub(freshAverageService, 'invalidateCache').resolves(true); const startDate = new Date('2023-01-01'); const endDate = new Date('2023-12-31'); const result = await freshAverageService.calculateMemberAverage(1, startDate, endDate); expect(result).to.deep.equal({ average: 200, games: 3, totalScore: 600 }); expect(mockModels.EventScore.findAll.called).to.be.true; }); }); describe('calculateMemberAverageByClubSetting', () => { it('클럽 설정에 따라 올바른 기간으로 평균을 계산해야 함', async () => { sandbox.stub(fs, 'mkdir').resolves(); sandbox.stub(fs, 'writeFile').resolves(); sandbox.stub(fs, 'readFile').rejects({ code: 'ENOENT' }); const calculateStub = sandbox.stub().resolves({ average: 185, games: 10, totalScore: 1850 }); mockModels.Member.findByPk.resolves({ id: 1, name: '테스트 회원' }); mockModels.Club.findByPk.resolves({ id: 1, name: '테스트 클럽', averageCalculationPeriod: '최근 3개월' }); const result = await freshAverageService.calculateMemberAverageByClubSetting(1, 1, { ...freshAverageService, calculateMemberAverage: calculateStub }); expect(result).to.deep.equal({ average: 185, games: 10, totalScore: 1850 }); expect(mockModels.Member.findByPk.called).to.be.true; expect(mockModels.Club.findByPk.called).to.be.true; expect(calculateStub.called).to.be.true; }); }); describe('invalidateMemberAverageCache', () => { it('회원 ID에 해당하는 캐시를 무효화해야 함', async () => { const invalidateCacheStub = sandbox.stub().resolves(true); const result = await freshAverageService.invalidateMemberAverageCache(1, { ...freshAverageService, invalidateCache: invalidateCacheStub }); expect(invalidateCacheStub.calledWith('average:1')).to.be.true; expect(result).to.be.true; }); }); });