[Canvas-불꽃놀이-22] TextParticle 클래스 단위 테스트

이전 글 : [Canvas-불꽃놀이-21] TailParticle 클래스 단위 테스트

 

[Canvas-불꽃놀이-21] TailParticle 클래스 단위 테스트

이전 글 : [Canvas-불꽃놀이-20] Particle 클래스 단위 테스트 [Canvas-불꽃놀이-20] Particle 클래스 단위 테스트이전 글 : [Canvas-불꽃놀이-19] CanvasOption 단위 테스트 [Canvas-불꽃놀이-19] CanvasOption 단위 테

jinsk-joy.tistory.com

 

TextParticle 단위 테스트 진행

 

TextParticle 클래스 단위 테스트 진행

  • TailParticle 클래스와 마찬가지로 TextParticle만의 멤버 변수와, 부모 메서드 호출, 고유 로직을 오류 없이 수행하는지 검증하도록 한다.

TextParticle 코드 전체

더보기
import Particle from "@/js/particle/Particle.js";
import { TEXT } from "@/js/constants.js";

class TextParticle extends Particle {
    /**
     * 불꽃놀이의 글자
     * @param {object} params
     * @param {CanvasRenderingContext2D} params.ctx
     * @param {boolean} isSmallScreen
     * @param {number} x
     * @param {number} y
     * @param {number} vx
     * @param {number} vy
     * @param {string} color
     */
    constructor({ ctx, isSmallScreen, x, y, vx, vy, color }) {
        super({ ctx, isSmallScreen, x, y, vx, vy, color });

        this.gravity = TEXT.GRAVITY;
    }

    update() {
        this.opacity -= TEXT.OPACITY_OFFSET;
        this.vy += this.gravity;
        super.update();
    }
}

export default TextParticle;

 

1.  공통 부분 설정

  • Particle 클래스를 상속하니 기본값 계산에 사용되는 메서드를 mock 함수화 한다.
// TextParticle.test.js
jest.mock("@/js/utils.js", () => ({
    randomFloat: jest.fn(),
    setRgbaColor: jest.fn(),
}));

  • 공통적으로 사용하는 ctx를 정의하고 isSmallScreen은 false로 테스트를 진행한다.
// TextParticle.js
describe("TextParticle 클래스 단위 테스트", () => {
	let ctx;
	const isSmallScreen = false;
	const { PARTICLE_DEFAULT_VALUES } = TEST_OPTION; // 파티클 멤버변수 기본값
    
    // 생략...
}

  • mock 함수화한 메서드의 반환값을 모든 테스트에 동일하게 적용하도록 한다.
// TextParticle.js
// Mock 함수 반환값 설정
beforeAll(() => {
    randomFloat.mockReturnValue(PARTICLE_DEFAULT_VALUES.opacity);
    setRgbaColor.mockReturnValue(PARTICLE_DEFAULT_VALUES.color);
});

  • 매번 테스트 전 ctx를 새롭게 설정하여 독립적으로 실행될 수 있도록 한다.
// TextParticle.js
// 테스트마다 ctx 새롭게 설정
beforeEach(() => {
    ctx = createMockCanvasCtx();
});

  • 테스트 종료 후 스파이에 대한 호출기록을 일괄적으로 삭제해 다음 테스트에 영향이 가지 않도록 한다.
// TextParticle.test.js
afterEach(() => {
    jest.clearAllMocks();
});

  • TextClass 고유의 멤버 변수가 있으므로 예상값과 결괏값이 일치하는 통합 메서드를 만들어 검증한다.
// TextParticle.js
function expectAllTextVars(text, params) {
    expectAllParticleVars(text, params);
    expect(text.gravity).toBe(TEXT.GRAVITY);
}

 

2.  생성자와 멤버변수 초기화 테스트

  • TextParticle은 외부에서 x, y, vx, vy, color을 전달받는다. 고유 멤버 변수인 gravity가 오류없이 초기화되는지 확인한다.
// TextParticle.js
test("TextParticle 생성자와 멤버변수 초기화", () => {
    const [x, y, vx, vy, color] = [10, 10, 1, 1, "hsla(30, 50%, 80%)"];
    const text = new TextParticle({ ctx, isSmallScreen, x, y, vx, vy, color });

    // 멤버변수의 결과값과 예측값이 일치하는지 검증
    expectAllTextVars(text, { ...PARTICLE_DEFAULT_VALUES, x, y, vx, vy, color });

    // 기본값을 계산할 때 randomFloat가 호출되는지 검증
    expect(randomFloat).toHaveBeenCalled();
});

 

3. draw 메서드 테스트

  • draw 메서드도 부모의 메서드를 그대로 사용하므로 상속받은 메서드가 잘 실행되는지 검증하도록 한다.
// TextParticle.js
test("TextParticle draw 테스트", () => {
    const text = new TextParticle({ ctx, isSmallScreen, x: 1, y: 1, vx: 10, vy: 10, color: "rgba(255, 255, 255, 1)" });
    
    // 부모의 draw 메서드의 호출 여부를 감시하기 위해 spy 추가
    const spyParticleDraw = jest.spyOn(Particle.prototype, "draw");
    text.draw();

    // 부모의 메서드가 실행됐는지 검증
    expect(spyParticleDraw).toHaveBeenCalledTimes(1);
});

 

4. update 메서드 테스트

  • 상속받은 부모의 update 로직은 이미 검증되었지만, TextParticle만의 업데이트 로직이 존재하므로 업데이트 후 멤버변수의 상태에 대해 검증하도록 한다.
// TextParticle.js
test("TextParticle update 테스트", () => {
    const [x, y, vx, vy, color] = [100, 100, 5, 5, "hsla(40, 50%, 50%)"];
    const text = new TextParticle({ ctx, isSmallScreen, x, y, vx, vy, color });

    // 부모의 업데이트 메서드를 감시하기 위해 jest spy에 추가
    const spyParticleUpdate = jest.spyOn(Particle.prototype, "update");
    text.update();

    // 업데이트 후 결과값과 예측값 검증
    const expectedVx = vx * PARTICLE_DEFAULT_VALUES.friction;
    const expectedVy = (vy + TEXT.GRAVITY) * PARTICLE_DEFAULT_VALUES.friction;
    const expectedResult = {
        ...PARTICLE_DEFAULT_VALUES,
        x: x + expectedVx,
        y: y + expectedVy,
        vx: expectedVx,
        vy: expectedVy,
        opacity: PARTICLE_DEFAULT_VALUES.opacity - TEXT.OPACITY_OFFSET,
        color,
    };
    expectAllTextVars(text, expectedResult);

    // 부모의 update 메서드가 호출되었는지 확인
    expect(spyParticleUpdate).toHaveBeenCalled();
});

 

5. reset 메서드 테스트

  • reset 메서드 역시 부모의 메서드를 그대로 사용하지만, TextParticle 클래스만의 고유한 멤버변수가 있고 효율적인 메모리 관리를 위해 오류 없이 진행되어야 하므로 reset후 멤버변수의 변화를 검증한다.

  • 사용한 파티클을 풀에 반납하기 위해 초기화를 진행할 경우
// TextParticle.js
test("TextParticle reset 테스트 - 사용된 파티클 풀에 반환시 초기화", () => {
    const text = new TextParticle({ ctx, isSmallScreen, x: 23, y: 32, vx: 5, vy: 5, color: "hsla(30, 100%, 100%)" });
    
    // 부모의 reset 메서드 감시를 위해 jest spy 추가
    const spyParticleReset = jest.spyOn(Particle.prototype, "reset");
    text.reset();

    // 리셋 후 멤버변수 상태 변화 검증
    expectAllTextVars(text, PARTICLE_DEFAULT_VALUES);

    // 부모의 메서드가 호출되었는지 검증
    expect(spyParticleReset).toHaveBeenCalled();
});

  • 호출 여부 검증은 위에서 확인되었으므로 풀에서 꺼내와 재사용을할 때 전달한 인자값이 제대로 적용되었는지 검증한다.
// TextParticle.js
test("TextParticle reset 테스트 - 풀에서 꺼내와서 재사용", () => {
    const text = new TextParticle({ ctx, isSmallScreen });

    const params = { x: 12, y: 45, vx: 0.5, vy: 2.3, color: "rgba(145, 255, 32, 0.8)" };
    text.reset(params);

    expectAllTextVars(text, { ...PARTICLE_DEFAULT_VALUES, ...params });
});

 

테스트 실행 결과

npx jest ./__test__/particle/TextParticle.test.js

 

Github Repo
 

GitHub - jinsk9268/text-fireworks

Contribute to jinsk9268/text-fireworks development by creating an account on GitHub.

github.com