프론트(feat Vue, Vuex)로 단위테스트 - 3 : Vuex TDD

김장훈·2020년 9월 24일
2

Vue단위테스트

목록 보기
3/4

Vuex를 TDD로 개발하자

한줄요약

  • 1) Vuex는 순수 js처럼 테스트를 작성한다.

Vuex는 생각보다 테스트 하기가 수월하다.

  • Vuex는 순수 js 파일이기에 다른 특별한 방법이나 모듈이 필요로 하지 않다.
  • Vuex의 기본적인 개념은 다루지 않는다.
  • 지금 만들고 있는 컴포넌트에서 Vuex로 다룰 수 있는 것들은 다음과 같다.
    • count를 state에서 관리한다.
    • 버튼을 클릭하면 action을 호출한다.
    • action은 state의 count의 mutation을 호출한다.
  • 테스트를 진행하기 전에 vuex를 따로 테스트 하므로 tests/unit/store/example를 만들어서 여기다 모듈 등으로 구분하여 테스트를 작성하고자 한다(이게 맞는건지는 의문)

state,getters 테스트

  • store.spec.js를 만들면 아무것도 없기에 에러가 바로 뜰 것이다. 우선 우리는 state의 값을, counter를 가져오는 테스트를 만들어야한다.
  • state를 직접 접근할 수 없으므로 getters 테스트를 만들자.
import { exampleStore as store } from '@/store/modules/example';

describe('example store test', () => {
  it('counter의 기본값은 0이 되어야한다', () => {
    expect(store.state.counter).toEqual(0);
  });
});
  • 간단한 fail 테스트는 이러한 모습이다.
  • state 에서 직접 값을 가져오지는 않지만 테스트를 위해서 작성해보았다.
  • 이제 store를 만들어주자.
// store/modules/example
export const exampleStore = {
  state: {
    counter: 0,
  },
};
  • 성공
  • state의 값을 직접 접근이 아니라 getters를 통해 가져오므로 getters 테스트를 추가하자
  • 상수타입으로 getter를 사용하려고 한다.
    이미지 구분용 문자
  • 출처 : https://beomy.tistory.com/86
  it('getters는 state의 counter를 가져온다', () => {
    const state = {
      counter: 0,
    };
    expect(store.getters.GET_COUNTER(state)).toEqual(state.counter);
  });
  • 상수 GET_COUNTER를 만들기 위해 모듈 내에 example-types.js를 추가하자
// store/modules/
export const GET_COUNTER = 'GET_COUNTER';
// store/modules/example
import { GET_COUNTER } from './example-types';
export const exampleStore = {
  state: {
    counter: 0,
  },
  getters: {
    [GET_COUNTER]: (state) => state.counter,
  },
};
  • 상수를 사용하여 getters를 추가, pass하게 만들었다.

mutations, actions 테스트

  • state의 값을 변경하려면 mutation을 사용해야한다.
  • 원하는 기능은 mutation을 호출 하여 값을 1 만큼 증가하는 것이다.
  it('counter의 값을 1 증가 시킨다', () => {
    const state = {
      counter: 0,
    };
    store.mutations.SET_COUNTER(state);
    expect(state.counter).toEqual(1);
  });
  • failed
  • 이제 상수를 활용하여 store를 작성하자.
// store/modules/example
import { GET_COUNTER, SET_COUNTER } from './example-types';
export const exampleStore = {
  state: {
    counter: 0,
  },
  getters: {
    [GET_COUNTER]: (state) => state.counter,
  },
  mutations: {
    [SET_COUNTER]: (state) => state.counter++,
  },
};
// store/modules/
export const GET_COUNTER = 'GET_COUNTER';
export const SET_COUNTER = 'SET_COUNTER';
  • 성공한다, 너무 쉽고 간단한 기능들이라 민망😂
  • 이제 actions을 구현해보자. 실제 로직을 생각하면 다음과 같다

    버튼 클릭 > actions의 메서드 호출 > (optional 로직수행) > mutations의 메서드 호출 > 숫자 증가

  • 우리가 작성하는 actions의 메서드는 특정 로직은 존재하지 않고 오직 위에서 작성한 SET_COUNTER를 호출하는 역할만 한다. 따라서 우리가 테스트 해야하는 부분은 SET_COUNTER를 호출하는지를 확인하는 것이다.
it('actions시 mutation을 호출 해야한다', () => {
    const commit = jest.fn();
    store.actions.SET_COUNTER({ commit });
    expect(commit).toHaveBeenCalledWith('SET_COUNTER');
  });
  • fail
  • mutation은 commit을 통해 호출 하므로 commit은 jest.fn()으로 만들어 주었다.
  • store를 마저 만들어주자.
// store/modules/example
import { GET_COUNTER, SET_COUNTER } from './example-types';
export const exampleStore = {
  state: {
    counter: 0,
  },
  getters: {
    [GET_COUNTER]: (state) => state.counter,
  },
  mutations: {
    [SET_COUNTER]: (state) => state.counter++,
  },
  actions: {
    [SET_COUNTER]: ({ commit }) => {
      commit(SET_COUNTER);
    },
  },
};
  • commit으로 SET_COUNTER를 받는데, 이 부분까지 확인이 완료 되었다.
  • counter가 증가되는 것을 확인할 수도 있겠지만 actions 로직 그 자체에 집중하려고 분리하였다.

이렇게 하여 정말 간단한 Vuex(store) 테스트가 완성되었다.

리팩토링

  • 이번 테스트는 너무 간단하여... 뭘 바꿔줄까라는 고민이 없었다. 그냥 중복 코드만 이전에 했던 것 처럼 앞으로 빼자.
import { exampleStore as store } from '@/store/modules/example';

describe('example store test', () => {
  let state;
  beforeEach(() => {
    state = {
      counter: 0,
    };
  });
  it('counter의 기본값은 0이 되어야한다', () => {
    expect(store.state.counter).toEqual(0);
  });

  it('getters는 state의 counter를 가져온다', () => {
    expect(store.getters.GET_COUNTER(state)).toEqual(state.counter);
  });

  it('counter의 값을 1 증가 시킨다', () => {
    store.mutations.SET_COUNTER(state);
    expect(state.counter).toEqual(1);
  });

  it('actions시 mutation을 호출 해야한다', () => {
    const commit = jest.fn();
    store.actions.SET_COUNTER({ commit });
    expect(commit).toHaveBeenCalledWith('SET_COUNTER');
  });
});
  • 간략하게 vuex 테스트가 모두 완성되었다.
profile
읽기 좋은 code란 무엇인가 고민하는 백엔드 개발자 입니다.

3개의 댓글

comment-user-thumbnail
2022년 4월 14일

장훈님 안녕하세요 하나 여쭤보고싶은게 있어서 글을 남겨요.
먼저 Jest이용한 TDD방식의 포스팅 덕분에 많은 도움이 되었습니다. :)
다름아니라 현재도 개발을 TDD방식으로 진행 중이신지 궁금하네요.
그리고 테스트 주도 개발 방식으로 진행 중이시라면 현재 느끼는 가장 큰 이점이 무엇이실까요?
만약 아니시라면 왜 TDD방식을 쓰지 않으시는지도 궁금하네요.
TDD를 도입해보고 싶어 선적용하여 공부 중인데 앞서 포스팅에 남기신 말씀처럼 10-30% 정도는 더 시간이 소요될 것으로 느껴집니다. 더군다나 예외상황에 경험이 없는 개발자가 진행시에 TDD가 크게 이점을 줄거같지 않다라는 생각을 하게 되었습니다. 프로젝트에 도입을 해보고싶은데 실제 쓰고 계신 개발자분들의 의견도 한번 듣고 싶어서 이렇게 글을 남기게 되었습니다. 말이 길었네요 ㅎㅎ 좋은 하루 되세요!

1개의 답글