이전 글 : [Canvas-불꽃놀이-28] Canvas 클래스 단위 테스트 (초기화)
Canvas 클래스 텍스트 파티클을 그리기 위한 TextData 생성 단위 테스트
TextData 생성 테스트
텍스트 픽셀 데이터는 캔버스에 그린 텍스트의 이미지 데이터를 가져와 텍스트가 그려진 부분만 추출한다.
텍스트 파티클을 그리기 위한 필수 데이터이므로 오류 없이 생성하는지 검증하도록 한다.
Canvas 클래스 텍스트 데이터 생성 부분 코드
더보기
/**
* @param {number} fontSize
* @returns {number} 사용자가 입력한 문자열의 width를 반환
*/
getTextWidth(fontSize) {
this.ctx.font = this.setFontStyle(fontSize);
return this.ctx.measureText(this.text).width;
}
adjustFontSize() {
const maxWidth = this.canvasCssWidth * SCREEN.MAX_WIDTH_RATIO;
let textWidth = this.getTextWidth(this.mainFontSize);
if (textWidth < maxWidth) return;
const minFontSize = this.mainFontSize * FONT.MIN_SIZE_RATIO;
let tempSize = this.mainFontSize;
while (textWidth > maxWidth && tempSize > minFontSize) {
tempSize *= FONT.ADJUST_RATIO;
textWidth = this.getTextWidth(tempSize);
}
if (tempSize < minFontSize) tempSize = minFontSize;
this.mainFontSize = this.setMainFontSize(tempSize);
this.subFontSize = this.setSubFontSize();
}
/**
* @param {number} fontSize
* @returns {object} 캔버스에 그려진 텍스트의 픽셀 데이터 반환
*/
getTextData(fontSize) {
const textData = new TextData(this.text, fontSize);
textData.drawText();
return textData.textPixelData;
}
createTextDatas() {
this.adjustFontSize();
this.mainTextData = this.getTextData(this.mainFontSize);
this.subTextData = this.getTextData(this.subFontSize);
}
1. 테스트 환경 공통 설정
- 캔버스 인스턴스, 텍스트를 그리기 위해 필요한 값, 중요 메서드 호출을 확인하기 위한 spy 변수를 전역에서 선언해 사용하도록 한다.
// CanvasTextData.test.js
describe("Canvas 클래스 textData 생성 테스트", () => {
let canvasInst;
const userInput = "텍스트 데이터 생성";
const fontSize = 100;
let spySetMainFontsize;
let spySetSubFontsize;
// 생략...
}
- 테스트 전 캔버스를 세팅하고 인스턴스를 생성해 테스트를 위한 공통부분을 미리 설정해 놓도록 한다.
메서드 호출 감시를 위한 스파이도 생성해 정의한다. - 텍스트가 끝난 뒤에는 호출 기록을 삭제해 다음 테스트에 영향이 가지 않도록 한다.
// CanvasTextData.test.js
// 테스트 진행 전
beforeEach(() => {
// 테스트용 캔버스 생성 및 설정
setTestCanvas();
// 테스트에 사용할 캔버스 인스턴스 생성과 설정
canvasInst = new Canvas();
canvasInst.text = userInput;
canvasInst.textLength = userInput.length;
canvasInst.mainFontSize = fontSize;
// 메서드 호출 확인을 위한 스파이 추가
spySetMainFontsize = jest.spyOn(canvasInst, "setMainFontSize");
spySetSubFontsize = jest.spyOn(canvasInst, "setSubFontSize");
});
// 테스트 진행 후 등록한 스파이의 호출 기록을 일괄적으로 초기화
afterEach(() => {
jest.clearAllMocks();
});
2. 문자열 width에 따른 폰트 크기 조절 테스트
- 문자열의 길이는 사용자의 입력에 따라 달라지므로 width를 미리 예측하기는 힘들다.
그렇기에 사용자가 텍스트를 입력했을 때 만약 텍스트의 width가 화면 width를 넘어버리면 글자가 일부분만 나타나기 때문에 의도한 효과가 나타나지 않는다. 그렇기에 미리 measureText를 통해 문자열의 width를 확인하여 화면 width에 맞춰 메인과 서브 폰트 사이즈를 조절하도록 한다.
// CanvasTextData.test.js
// 문자열의 width가 최대 width 미만일 때
test("adjustFontSize 테스트 | textWidth가 maxWidth 미만일 때", () => {
// getTextWidth 메서드 mocking 하여 maxWidth보다 작은 값을 리턴하도록 설정
canvasInst.getTextWidth = jest.fn(() => fontSize);
canvasInst.adjustFontSize();
// textWidth < maxWidth이면 폰트 사이즈 수정없이 그대로 사용할 수 있다.
// 이에 따라 폰트 사이즈를 세팅하는 메서드는 호출되지 않고 mainFontSize는 기존의 사이즈와 동일하다.
expect(spySetMainFontsize).not.toHaveBeenCalled();
expect(spySetSubFontsize).not.toHaveBeenCalled();
expect(canvasInst.mainFontSize).toBe(fontSize);
});
// 문자열의 widthrk 최대 width 이상일 때
test("adjustFontSize 테스트 | textWidth가 maxWidth 이상일 때", () => {
// getTextWidth 메서드 mocking 하여 maxWidth 이상값을 리턴하도록 설정
canvasInst.getTextWidth = jest.fn((tempSize) => tempSize * 10);
canvasInst.adjustFontSize();
// 설정한 textWidth 값은 1,000이고 maxWidth는 900이다.
// 예상 사이즈는 계산이 간단하므로 수기계산하여 로직이 맞는지 검증한다.
// (폰트 조정 비율 FONT.ADJUST_RATIO를 반복 적용해 예상값을 계산)
const expectedTempSize = 85.7375;
const expectedMainFontSize = Math.round(expectedTempSize);
// textWidth < maxWidth면 폰트사이즈를 재계산해 지정해야한다.
// 그 과정에서 폰트 사이즈를 지정하는 메서드가 호출되었는지 확인하고 예상값과 일치하는지 검증한다.
expect(spySetMainFontsize).toHaveBeenCalledWith(expectedTempSize);
expect(spySetMainFontsize).toHaveBeenCalledTimes(1);
expect(canvasInst.mainFontSize).toBe(expectedMainFontSize);
expect(spySetSubFontsize).toHaveBeenCalledTimes(1);
expect(canvasInst.subFontSize).toBe(Math.round(expectedMainFontSize * FONT.SUB_RATIO));
});
3. TextData 생성 테스트
- 텍스트 데이터를 생성하려면 TextData클래스의 drawText 메서드가 호출해야한다. 스파이로 등록해 호출되었는지 확인하도록 한다.
- drawText는 이미 검증이 끝난 메서드 이므로 간단히 데이터가 잘 대입되었는지, 테스트로 생성한 ImageData.data의 타입이 실제 타입과 일치하는지 확인하도록 한다.
// CanvasTextData.test.js
test("createTextDatas 테스트", () => {
// drawText 메서드 호출을 감시하기 위해 스파이 등록
const spyDrawText = jest.spyOn(TextData.prototype, "drawText");
canvasInst.createTextDatas();
// main과 sub 폰트 2개를 그리므로 호출 횟수가 2인지 검증
expect(spyDrawText).toHaveBeenCalledTimes(2);
// main과 sub의 TextData가 빈 객체가 아닌지 확인하고
// TextData의 data의 타입이 Unit8ClampedArray와 일치하는지 검증한다.
expect(canvasInst.mainTextData).not.toEqual({});
expect(canvasInst.mainTextData.data).toBeInstanceOf(Uint8ClampedArray);
expect(canvasInst.subTextData).not.toEqual({});
expect(canvasInst.subTextData.data).toBeInstanceOf(Uint8ClampedArray);
});
테스트 결과
npx jest .__test__/canvas/CanvasTextData.test.js
Github Repo
'Canvas > 불꽃놀이 프로젝트' 카테고리의 다른 글
[Canvas-불꽃놀이-31] Canvas 클래스 단위 테스트 (파티클 업데이트) (1) | 2024.12.19 |
---|---|
[Canvas-불꽃놀이-30] Canvas 클래스 단위 테스트 (파티클 생성) (1) | 2024.12.19 |
[Canvas-불꽃놀이-28] Canvas 클래스 단위 테스트 (초기화) (1) | 2024.12.17 |
[Canvas-불꽃놀이-27] CanvasOption 클래스 단위 테스트 (1) | 2024.12.17 |
[Canvas-불꽃놀이-26] TextData 클래스 단위 테스트 (1) | 2024.12.11 |