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

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

 

[Canvas-불꽃놀이-20] Particle 클래스 단위 테스트

이전 글 : [Canvas-불꽃놀이-19] CanvasOption 단위 테스트 [Canvas-불꽃놀이-19] CanvasOption 단위 테스트이전 글 : [Canvas-불꽃놀이-18] utils.js 단위 테스트 [Canvas-불꽃놀이-18] utils.js 단위 테스트이전 글 : [C

jinsk-joy.tistory.com

 

TailParticle 클래스 단위 테스트 진행

 

TailParticle 단위 테스트

  • 부모 파티클인 Particle 클래스의 검증이 끝났으니 TailParticle 클래스도 단위 테스트를 진행하도록 한다.
  • 부모의 속성, 기능이 TailParticle을 통해서 잘 수행되고 있는지, TailParticle 클래스만의 고유 멤버변수와, 메서드가 잘 작동하는지 검증하도록 한다.

TailParticle 전체 코드

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

class TailParticle extends Particle {
    /**
     * 불꽃놀이의 꼬리
     * @param {object} params
     * @param {CanvasRenderingContext2D} params.ctx
     * @param {boolean} params.isSmallScreen
     * @param {number} params.x
     * @param {number} params.y
     * @param {number} params.vy
     */
    constructor({ ctx, isSmallScreen, x, y, vy }) {
        super({ ctx, isSmallScreen, x, y, vy });
        this.initTailParticleVars();
    }

    initTailParticleVars() {
        this.initialX = this.x;
        this.radian = TAIL.RADIAN;
    }

    update() {
        this.vy *= this.friction;
        this.vx = Math.cos(this.radian) * this.vy * TAIL.X_ADJUST_RATE;

        this.opacity = -this.vy;
        this.radian += TAIL.RADIAN_OFFSET;

        this.updatePosition();
        this.x += (this.initialX - this.x) * TAIL.INITIAL_X_RETURN_RATE;
    }

    /**
     * TailParticle 멤버 변수 초기화
     * @param {object} [params]
     */
    reset(params) {
        super.reset(params);
        this.initTailParticleVars();
    }
}

export default TailParticle;

 

1. 공통부분 설정

  • 부모의 메서드를 사용하므로 Particle 클래스에서 진행한 공통 설정을 적용한다.
// TailParticle.test.js 
// 기본값 설정 시 사용되는 메서드 Mock 함수화
jest.mock("@/js/utils", () => {
    return {
        randomFloat: jest.fn(),
        setRgbaColor: jest.fn(),
    };
});
// TailParticle.js
describe("TailParticle 클래스 단위 테스트", () => {
    // 공통 속성 전역 변수 설정
    let ctx;
    let isSmallScreen;
    const { PARTICLE_DEFAULT_VALUES } = TEST_OPTION;

    // Mock 함수 반환값 설정
    beforeAll(() => {
        randomFloat.mockReturnValue(PARTICLE_DEFAULT_VALUES.opacity);
        setRgbaColor.mockReturnValue(PARTICLE_DEFAULT_VALUES.color);
    });

    // 공통 속성 초기화
    beforeEach(() => {
        ctx = createMockCanvasCtx();
        isSmallScreen = false;
    });
    
    // 테스트 종료 후 등록된 스파이의 호출기록을 일괄적으로 삭제
    afterEach(() => {
        jest.clearAllMocks();
    });
    
    /**
     * TailParticle 클래스 모든 멤버변수 검증
     * @param {TailParticle} tail
     * @param {object} expectedResult
     * @param {number} expectedInitialX
     * @param {number} expectedRadian
     */
    function expectAllTailVars(tail, expectedResult, expectedInitialX, expectedRadian) {
        expectAllParticleVars(tail, expectedResult);
        expect(tail.initialX).toBe(expectedInitialX);
        expect(tail.radian).toBe(expectedRadian);
    }
}

 

2. TailParticle 생성자와 멤버변수 초기화 검증

  • TailParticle을 생성할 때 전달할 값은 x, y, vy 이고 고유의 멤버변수는 initialX, radian이다.
    기본값으로 설정되는 멤버변수와 더불어 생성한 TailParticle 초기화가 제대로 이루어지는지 검증한다.
  • 기본값 계산 시 사용된 메서드도 호출이 되었는지 추가로 검증하도록 한다.
test("TailParticle 생성자와 멤버변수 초기화", () => {
    // TailParticle 생성시 필요한 인자: x, y, vy
    const [x, y, vy] = [100, 100, 1];
    const tail = new TailParticle({ ctx, isSmallScreen, x, y, vy });

    // 생성된 TailParticle의 모든 속성이 예측값과 일치하는지 검증
    expectAllTailVars(tail, { ...PARTICLE_DEFAULT_VALUES, x, y, vy }, x, TAIL.RADIAN);

    // 기본값 설정 시 사용되는 메서드 호출 여부 검증
    expect(randomFloat).toHaveBeenCalled();
    expect(setRgbaColor).toHaveBeenCalled();
});

 

3. draw 메서드 테스트

  • TailParticle에서는 부모의 draw 메서드를 그대로 사용한다. 부모의 메서드는 이미 검증되었으므로 TailParticle이 부모인 Particle의 draw 메서드를 실행하는지 확인하도록 한다.
  • Particle 클래스 자체는 정적 메서드를 가리키므로, 인스턴스 메서드는 감시되지않는다. 
    Particle 클래스의 인스턴스 메서드는 prototype 체인에 정의되어 있으므로 인스턴스 메서드를 감시하려면 Particle.prototype을 사용해야 한다. Particle.draw을 사용하면 메서드가 정적 메서드가 아니므로 찾을 수 없다고 나온다. (참고)

Particle.prototype을 사용해야하는 이유

// TailParticle.js
test("TailParticle draw 테스트", () => {
    const tail = new TailParticle({ ctx, isSmallScreen, x: 10, y: 5, vy: 2 });

    // 부모의 draw 함수 호출 여부를 감시하기위해 jest spy 추가 (인스턴스 메서드이므로 prototype 사용)
    const spyTailDraw = jest.spyOn(Particle.prototype, "draw");
    tail.draw();

    // draw 함수가 1번만 실행되었는지 검증
    expect(spyTailDraw).toHaveBeenCalledTimes(1);
});

 

4. update 메서드 테스트

  • update 메서드에선 TailParticle의 추가 업데이트 로직도 포함되어 있으므로 실행 후 전체 멤버변수의 예측값을 검증한다.
  • 부모의 update 메서드가 제대로 호출되는지 검증한다.
test("TailParticle update 테스트", () => {
    const [x, y, vy] = [10, 10, 1];
    const tail = new TailParticle({ ctx, isSmallScreen, x, y, vy });

    // 부모의 update 함수 호출을 감시하기위해 jest spy에 추가
    const spyUpdatePosition = jest.spyOn(Particle.prototype, "updatePosition");
    tail.update();

    // 결과 예측값 계산
    const expectedVY = vy * PARTICLE_DEFAULT_VALUES.friction;
    const expectedVX = Math.cos(TAIL.RADIAN) * expectedVY * TAIL.X_ADJUST_RATE;
    const expectedX = x + expectedVX;
    const expectedResult = {
        ...PARTICLE_DEFAULT_VALUES,
        vy: expectedVY,
        vx: expectedVX,
        x: expectedX + (x - expectedX) * TAIL.INITIAL_X_RETURN_RATE,
        y: y + expectedVY,
        opacity: -expectedVY,
    };
    // 업데이트된 TailParticle의 모든 속성이 예측값과 일치하는지 검증
    expectAllTailVars(tail, expectedResult, x, TAIL.RADIAN + TAIL.RADIAN_OFFSET);

    // 부모의 업데이트 함수 실행 여부 검증
    expect(spyUpdatePosition).toHaveBeenCalledTimes(1);
});

 

5. reset 메서드 테스트

  • TailParticle 클래스 만의 고유 멤버변수가 있다.
    고유 멤버변수를 포함하여 모든 멤버변수가 사용 후 초기화하여 풀에 반환, 풀에서 가져와 재사용 초기화가 오류없이 이루어지는지 검증하도록 한다.

  • 사용한 TailParticle을 초기화 한 후 풀에 반환 검증
// TailParticle.js
test("TailParticle reset 테스트 - 사용된 파티클 풀에 반환시 초기화", () => {
    const tail = new TailParticle({ ctx, isSmallScreen, x: 3, y: 5, vy: 1 });
    
    // reset 메서드 호출을 감시하기 위해 jest spy 추가
    const spyParticleReset = jest.spyOn(Particle.prototype, "reset");
    const spyInitTailParticleVars = jest.spyOn(tail, "initTailParticleVars");
    
    // radian이 TailParticle 초기값으로 설정되는지 확인을 위해 업데이트 진행
    tail.update();

    // 사용된 파티클 풀에 반환하기 위해 초기화
    tail.reset();

    // 초기화된 TailParticle 모든 속성이 예측값과 일치하는지 검증
    expectAllTailVars(tail, PARTICLE_DEFAULT_VALUES, 0, TAIL.RADIAN);

    // 리셋과 리셋시 기본값 계산때 사용된 메서드 호출여부 검증
    expect(spyParticleReset).toHaveBeenCalledTimes(1);
    expect(spyInitTailParticleVars).toHaveBeenCalledTimes(1);
});

  • 풀에서 가져와 재사용을 위한 초기화 검증하고 reset 호출 검증은 이미 검증되었으므로 생략하도록 한다.
// TailParticle.js
test("TailParticle reset 테스트 - 풀에서 꺼내와서 재사용", () => {
    const tail = new TailParticle({ ctx, isSmallScreen });

    // 풀에서 초기화된 TailParticle 가져와서 재사용
    const params = { x: 100, y: 100, vy: 10 };
    tail.reset(params);

    // 재사용된 TailParticle 모든 속성이 예측값과 일치하는지 검증
    expectAllTailVars(tail, { ...PARTICLE_DEFAULT_VALUES, ...params }, params.x, TAIL.RADIAN);
});

 

테스트 결과

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

 

Github Repo
 

GitHub - jinsk9268/text-fireworks

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

github.com