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

김장훈·2020년 9월 26일
0

Vue단위테스트

목록 보기
4/4

사실 이것은 단위테스트가 아니다.

  • 최소한의 기능 테스트라고 하기엔 '연동 테스트'는 단위테스트라곤 할 수 없다. 그래서 그냥.. 끼워넣었다.
  • 이 테스트의 목적은 실제 컴포넌트 - vue(model) - vuex가 잘 연동이 되는가를 확인하는 것이다.
  • 다시 우리의 간단한 컴포넌트를 보자
  • 기존에 우리가 컴포넌트에서 가져오던 '0'은 이제 vuex에서 가져와야한다.
  • 클릭을 하게 되면 actions-mutation을 발생시켜야 한다.
  • 변경된 값은 즉각 반영이 되어야한다.
  • 이 순서대로 테스트를 작성해보자(아마 리팩토링 처럼 될 것이다)

getters 연동

  • 이제 기존에 작성했던 부분이 바뀌어야한다.
  it('기본 영역을 확인하자 : 숫자 나오는 부분', () => {
    const count = wrapper.find('.count-area').text();
    expect(count).toBe('0');
  });
  • expect 하는 부분은 동일 하나 컴포넌트를 생성하는 부분이 변경되어야한다.
  • Vuex는 vue 전체를 관리한다. 그러나 우리가 테스트 하고자 하는건 이 컴포넌트 내에서만이다. 그렇기에 우리는 테스트시에 굳이 Vuex를 다 띄울 필요가 없다.
  • 이를 위해서 기본적으로 해줘야하는 부분이 있다.
// tests/unit/example/button.spec.js
import { shallowMount, createLocalVue } from '@vue/test-utils';
import ButtonPage from '@/components/example/ButtonPage';
import Vuex from 'vuex';
import { exampleStore } from '@/store/modules/example';

const localVue = createLocalVue();
localVue.use(Vuex);
  • 우리가 만든 store와 이를 사용하기 위한 다른 메서드 등을 import 해준다.
  • 그리고 이를 컴포넌트를 만들때 같이 넣어준다.
describe('ButtonClick', () => {
  let wrapper;
  let mockSomeMethod;
  let store;
  beforeEach(() => {
    store = new Vuex.Store({
      modules: {
        exampleStore,
      },
    });
    mockSomeMethod = jest.spyOn(ButtonPage.methods, 'someMethod');
    wrapper = shallowMount(ButtonPage, { store, localVue });
  });
	...
});
  • 이제 테스트 환경을 변경해주었다. 우리가 작성한 store는 모듈 형태이므로 store를 넣어줄때 저렇게 modules에 넣어주어야한다.
  • 이제는 컴포넌트를 변경해주어야한다. data에서 받던 부분을 삭제하고 computed와 getters를 연동하자. 그리고 이때 helper를 사용해보자.
<template>
  <div>
    <div class="count-show">
      <span class="count-area">{{ counter }}</span>
    </div>
    <div>
      <button class="increment-btn" @click="someMethod('name')">
        Click Me
      </button>
    </div>
  </div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
  data() {
    return {};
  },
  computed: {
    ...mapGetters({ counter: 'GET_COUNTER' }),
  },
  methods: {
    someMethod() {
      console.log('someMethod');
    },
    doSomething(number) {
      return number % 2 == 0 ? true : false;
    },
  },
};
</script>
  • counter를 이제는 vuex에서 가져오게 되었고 computed하기에 데이터 변경시 바로 변경분이 적용된다.

actions 연동

  • 이제 버튼을 클릭해서 counter을 바꿔보자

    버튼 클릭 > actions > mutations > state

it('버튼을 클릭하면 counter가 +1 증가되어야한다', () => {
    const btn = wrapper.find('.increment-btn');
    btn.trigger('click');
    expect(store.state.exampleStore.counter).toEqual(1);
  });
  • 바로 component도 변경해보자
<template>
  <div>
    <div class="count-show">
      <span class="count-area">{{ counter }}</span>
    </div>
    <div>
      <button class="increment-btn" @click="someMethod('name')">
        Click Me
      </button>
    </div>
  </div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
  data() {
    return {};
  },
  computed: {
    ...mapGetters({ counter: 'GET_COUNTER' }),
  },
  methods: {
    ...mapActions({ increment: 'SET_COUNTER' }),
    someMethod() {
      this.increment();
      console.log('someMethod');
    },
    doSomething(number) {
      return number % 2 == 0 ? true : false;
    },
  },
};
</script>
  • 기존의 테스트 코드는 그대로 두고 싶어서 @click 메서드를 변경하지 않고 그 안에 mapActions를 두었다.
  • @click에 바로 actions 메서드를 붙여도 된다.
  • 하지만 우리의 테스트는 Fail...
    Expected: 1
    Received: 3
  • 위에서 테스트를 하면서 기본 set이 깨끗히 정리가 안되서 그런듯 하다. 이를 정리해주자.
beforeEach(() => {
    exampleStore.state.counter = 0;
    store = new Vuex.Store({
      modules: {
        exampleStore,
      },
    });
    mockSomeMethod = jest.spyOn(ButtonPage.methods, 'someMethod');
    wrapper = shallowMount(ButtonPage, { store, localVue });
  });
  • 테스트가 돌때마다(beforeEach) counter = 0이 된다. 지금은 일단 이렇게 임시방편으로 넣었지만 테스트 종료시 셋업을 리셋 해줄 수 있다.

마무리

  • 따로 리팩토링할 부분이 없어서 이렇게 마무리를 하려고 한다. 막 엄청난 스킬은 아니고 단지 나처럼 프론트 TDD를 처음 접하시는 분들에게 조금이나마 도움이 되길 바랄 뿐이다.
profile
읽기 좋은 code란 무엇인가 고민하는 백엔드 개발자 입니다.

0개의 댓글