Vue TDD

Vue TDD - Component ํŽธ

2020. 7. 25. 00:54
๋ชฉ์ฐจ
  1. Table of Content
  2. ๐Ÿ“Œ 00. Introduction
  3. ๐Ÿ“Œ 01. Testing Data
  4. ๐Ÿ“Œ 02. Testing Methods
  5. ๐Ÿ“Œ 03. Testing Created
  6. ๐Ÿ“Œ 04. Testing Props
  7. ๐Ÿ“Œ 05. Testing Computed
  8. ๐Ÿ“Œ Testing vuex in component
  9. ๐Ÿ“Œ Conclusion
  10. Reference
๋ฐ˜์‘ํ˜•

Table of Content

    1. Introduction
    1. Testing Data
    1. Testing Methods
    1. Testing Created
    1. Testing Props
    1. Testing Computed
    1. Testing vuex in component
    1. Conclusion
  • Reference

๐Ÿ“Œ 00. Introduction

๐Ÿšจ์ฃผ์˜: ํ•ด๋‹น๊ธ€์€ ํ™˜๊ฒฝ์„ค์ •์„ ๋‹ค๋ฃจ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์ธ cli๋กœ jest๋ฅผ ์„ค์ •ํ•œ ํŒŒ์ผ์„ ํ† ๋Œ€๋กœ ์„ค๋ช…์„ ํ•ฉ๋‹ˆ๋‹ค.

์ด ํฌ์ŠคํŒ…์—๋Š” Vue component๋ฅผ ์–ด๋–ป๊ฒŒ testing์„ ํ• ๊นŒ? ์— ๋Œ€ํ•œ ๋ฌผ์Œ์— ๋‹ต๋ณ€์„ ํ•˜๋Š” ๊ธ€์ž…๋‹ˆ๋‹ค. ํ•ด๋‹น ๊ธ€์˜ ์ฝ”๋“œ๋Š” vue-test-practice์— ๊ฐ€์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด ํฌ์ŠคํŒ…์—์„œ ๋‹ค๋ฃฐ ์ปดํฌ๋„ŒํŠธ๋Š” ํ•˜๋‚˜์ด๋ฉฐ ๊ฐ„๋‹จํ•œ Counter๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋Š” ์˜ˆ์ œ๋กœ ์„ค๋ช…์„ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  tdd์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ tdd cycle์„ ์ค€์ˆ˜ํ•˜์—ฌ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

MyCounter.vue์˜ ๊ธฐ๋Šฅ:

  • count๊ฐ’์€ ํ•ญ์ƒ display๋˜์–ด์•ผ ํ•œ๋‹ค.(์ดˆ๊ธฐ ๊ฐ’ 0)
  • ํ”Œ๋Ÿฌ์Šค ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด count ๊ฐ’์ด ์ฆ๊ฐ€ํ•œ๋‹ค.
  • ๋งˆ์ด๋„ˆ์Šค ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด count ๊ฐ’์ด ๊ฐ์†Œํ•œ๋‹ค.

ํ•ด๋‹น ๊ธฐ๋Šฅ์€ ์‹ค์ œ๋กœ Data์™€ Method๋ฐ–์— ๊ตฌํ˜„์ด ์•ˆ๋จ์œผ๋กœ ์ถ”๊ฐ€์ ์œผ๋กœ created, props, computed๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋กœ ์„ค๋ช…ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ 01. Testing Data

์ฒซ๋ฒˆ์งธ๋กœ data๊ฐ’์—๋Š” count๊ฐ€ 0์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋ ‡๊ฒŒ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

//MyCounter.spec.js
import { mount } from '@vue/test-utils';
import MyCounter from '@/components/MyCounter';

describe('MyCounter unit test', () => {
  // mount component
  const wrapper = mount(MyCounter);
  const { vm } = wrapper;

   // 
   describe('MYCOUNTER DATA TEST', () => {
    describe('data count test', () => {
      it('count should be 0', () => {
        expect(vm.count).toBe(0); // data์˜ count์—๋Š” 0์ด ๋“ค์–ด์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
      });
    });
  });
}

๐Ÿš€ ๊นจ์•Œ์ง€์‹

mount์™€ shallow mount์˜ ์ฐจ์ด์ .

mount๋Š” vue ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ props๋‚˜ trigger click์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
shallow mount๋Š” ์ž์‹ ์ปดํฌ๋„ˆ๋Š”ํŠธ๋Š” ๋žœ๋”๋งํ•˜์ง€ ์•Š๋Š”๋‹ค.

// MyCounter.vue
export default {
  name: 'MyCounter',
  data() {
    return {
      count: 0,
    };
  },
};

๐Ÿ“Œ 02. Testing Methods

counter์˜ ๊ฐ’์„ ์กฐ์ •ํ•˜๊ธฐ์œ„ํ•ด ๋‘๊ฐœ์˜ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • onClickIncrease (counter์˜ ๊ฐ’์„ 1 ์ฆ๊ฐ€์‹œํ‚ค๋Š” ํ•จ์ˆ˜)
  • onClickDecrease (counter์˜ ๊ฐ’์„ 1 ๊ฐ์†Œ์‹œํ‚ค๋Š” ํ•จ์ˆ˜)
describe('MyCounter unit test', () => {
  // testing methods
  describe('MYCOUNTER METHOD TEST', () => {
    // ๋งค ํ…Œ์ŠคํŠธ ์ „์— count์˜ ๊ฐ’์„ 0์œผ๋กœ ์ดˆ๊ธฐํ™” ์‹œํ‚จ๋‹ค.
    beforeEach(() => {
      vm.count = 0;
    });
    // testing increase method
    describe('onClickIncrease test', () => {
      it('increase by 1', () => {
        vm.onClickIncrease(); // count๋ฅผ ์ฆ๊ฐ€ ์‹œ์ผœ๋ณธ๋‹ค.
        expect(vm.count).toBe(1);
      });
    });

    // testing decrease method
    describe('onClickDecrease test', () => {
      it('decrease by 1', () => {
        vm.onClickDecrease(); // count๋ฅผ ๊ฐ์†Œ ์‹œ์ผœ๋ณธ๋‹ค.
        expect(vm.count).toBe(-1);
      });
    });
  });
});

Vue์ฝ”๋“œ๋Š” ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export default {
  name: 'MyCounter',
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    onClickIncrease() {
      this.count += 1;
    },
    onClickDecrease() {
      this.count -= 1;
    },
  },
};

๐Ÿ“Œ 03. Testing Created

๊ธฐ๋Šฅ

  • created๋ ๋•Œ data.testCreated์— 'TEST_CREATED'๋ฅผ ์„ธํŒ…ํ•ด์ค€๋‹ค.
// testing created
  describe('MYCOUNTER CREATED TEST', () => {
    describe('created test', () => {
      it('testCreated data should be changed blank to TEST_CREATED', () => {
        expect(vm.testCreated).toBe('TEST_CREATED');
      });
    });
  });
export default {
  name: 'MyCounter',
  created() {
    this.testCreated = 'TEST_CREATED';
  },
  data() {
    return {
      testCreated: '',
    };
  },
};

๐Ÿ“Œ 04. Testing Props

๋จผ์ € props๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ shallow mount๊ฐ€ ์•„๋‹Œ mount๋กœ ์„ค์ •์„ ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

import { mount } from '@vue/test-utils';
import MyCounter from '@/components/MyCounter';

describe('MyCounter unit test', () => {
  // mount component
  const wrapper = mount(MyCounter, {
    propsData: {
      testProps: 'TEST_PROPS', // ์ด๋ ‡๊ฒŒ ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    },
  });
  const { vm } = wrapper;

  // testing props
  describe('MYCOUNTER PROPS TEST', () => {
    describe('testProps test', () => {
      it('testProps should be "TEST_PROPS', () => {
        expect(vm.testProps).toBe('TEST_PROPS');
      });
    });
  });
});
export default {
  name: 'MyCounter',
  props: {
    testProps: {
      type: String,
    },
  },
};

๐Ÿ“Œ 05. Testing Computed

๊ธฐ๋Šฅ:

data.tempText('HELLO')๋ฅผ ์†Œ๋ฌธ์ž๋กœ ์ถœ๋ ฅํ•˜๋Š” computed

describe('MYCOUNTER DATA TEST', () => {
  // testing computed
  describe('MYCOUNTER COMPUTED TEST', () => {
    it('lowercaseTempText test', () => {
      expect(vm.lowercaseTempText).toBe('hello');
    });
  });
});
export default {
  name: 'MyCounter',
  data() {
    return {
      tempText: 'HELLO',
    };
  },
  computed: {
    lowercaseTempText() {
      return this.tempText.toLowerCase();
    },
  },
};

๐Ÿ“Œ Testing vuex in component

component์—์„œ vuex์˜ test ์‹œ์ž‘์€ mock์—์„œ ๋ถ€ํ„ฐ ์ถœ๋ฐœ ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๋กœ์ง์ด ์ˆ˜ํ–‰์ด ๋˜๋Š”๊ฑด ๋”ฐ๋กœ vuex์—์„œ ํ…Œ์ŠคํŠธ ํ•ด์ฃผ์„ธ์š”.

// ๋จผ์ € vuex๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค.
import Vuex from 'vuex';
import { mount, createLocalVue } from '@vue/test-utils';
import MyCounter2 from '../../src/components/MyCounter2.vue';

// ์ด๋ ‡๊ฒŒ localVue์—์„œ vuex๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
const localVue = createLocalVue();
localVue.use(Vuex);

describe('MyCounter2 test', () => {
  let store;
  let state;
  let actions;
  let mutations;
  let wrapper;
  let vm;
  beforeEach(() => {
    state = {
      count: 0,
    };
    mutations = {
      ['INCREMENT']: jest.fn(),
      ['DECREMENT']: jest.fn(),
    };
    actions = {
      ['FETCH_ITEMS']: jest.fn(),
    };
    store = new Vuex.Store({
      modules: {
        counter: {
          namespaced: true,
          state,
          mutations,
          actions,
        },
      },
    });
    wrapper = mount(MyCounter2, { store, localVue });
    vm = wrapper.vm;
  });
  it('count mock', async () => {
    expect(vm.count).toBe(0);
  });
  it('mutations mock', () => {
    const incBtn = wrapper.find('#incBtn');
    incBtn.trigger('click');
    expect(mutations.INCREMENT).toHaveBeenCalled();

    const decBtn = wrapper.find('#decBtn');
    decBtn.trigger('click');
    expect(mutations.DECREMENT).toHaveBeenCalled();
  });
  it('actions mock', () => {
    const fetchBtn = wrapper.find('.fetchBtn');
    fetchBtn.trigger('click');
    expect(actions.FETCH_ITEMS).toHaveBeenCalled();
  });
});

๐Ÿ“Œ Conclusion

๋ทฐ์˜ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ๋Š” ์‚ฌ์‹ค ๊ทธ๋ ‡๊ฒŒ ์–ด๋ ต์ง€ ์•Š์Šต๋‹ˆ๋‹ค.. ํ•˜์ง€๋งŒ ์‹ค๋ฌด์—์„œ ์ ์šฉํ•˜๊ธฐ๋Š” ์ƒ๋‹นํžˆ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๊ทธ์ด์œ ๋Š” ๊ฐ์ข… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค๊ณผ utils๋“ค ๋•Œ๋ฌธ์— ์˜์กด์„ฑ ๋ฌธ์ œ ๋•Œ๋ฌธ์— test๊ฐ€ ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค. ์ด๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ตœ๋Œ€ํ•œ logic์„ store๋กœ ๋นผ์„œ logic์ ์ธ unit test๋Š” store์—์„œ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ View์™€ Store๋ฅผ ๋ถ„๋ฆฌ๋ฅผ ํ•˜์—ฌ View์—์„œ๋Š” snapshot ํ…Œ์ŠคํŠธ, storybook, ํ˜น์€ e2eํ…Œ์ŠคํŠธ๋กœ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๊ณ  store๋Š” unit์œผ๋กœ ํ…Œ์ŠคํŒ…์„ ํ•˜๋Š”๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ๋Š” store๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Reference

  • ๋ทฐ ๊ณต์‹๋ฌธ์„œ
  • Jest์™€ Vue Test Utils๋กœ Vue ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
  • ์นด์นด์˜คํ…Œํฌ__๋ฐ”๋‹ฅ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” Vue ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ
๋ฐ˜์‘ํ˜•

'Vue TDD' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Vue TDD - ํšŒ๊ณ ํŽธ  (0) 2020.08.10
Test code ์‰ฝ๊ฒŒ ์“ฐ๊ธฐ - 1  (0) 2020.08.06
Vue TDD - E2E ํŽธ  (0) 2020.08.02
Vue TDD - Storybook ํŽธ  (0) 2020.07.31
Vue TDD - Vuex ํŽธ  (0) 2020.07.30
  1. Table of Content
  2. ๐Ÿ“Œ 00. Introduction
  3. ๐Ÿ“Œ 01. Testing Data
  4. ๐Ÿ“Œ 02. Testing Methods
  5. ๐Ÿ“Œ 03. Testing Created
  6. ๐Ÿ“Œ 04. Testing Props
  7. ๐Ÿ“Œ 05. Testing Computed
  8. ๐Ÿ“Œ Testing vuex in component
  9. ๐Ÿ“Œ Conclusion
  10. Reference
'Vue TDD' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Test code ์‰ฝ๊ฒŒ ์“ฐ๊ธฐ - 1
  • Vue TDD - E2E ํŽธ
  • Vue TDD - Storybook ํŽธ
  • Vue TDD - Vuex ํŽธ
eddie0329
eddie0329
Front-end Developer
๋ฐ˜์‘ํ˜•
eddie0329
Eddie Sunny's Blog
eddie0329
์ „์ฒด
์˜ค๋Š˜
์–ด์ œ
  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (100)
    • Summary of Book (0)
    • Vue Study (11)
    • Vue TDD (9)
    • Vue BDD (5)
    • Design Pattern (9)
    • Javascript Study (3)
    • React Study (15)
    • React TDD (1)
    • Vue Storybook (2)
    • Refactoring (0)
    • Graphql_Apollo (3)
    • Svelte (8)
    • Open Source (1)
    • D3 (4)
    • Typescript (1)
    • CSS (2)
    • Android (0)
    • Java (0)
    • Kotlin (0)
    • ์žก๋‹ด (0)
    • Swift (19)
    • Rust (2)
    • ํšŒ์‚ฌ์ด์•ผ๊ธฐ (2)
    • ReactNative Study (2)
    • Vitest (0)

๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

  • Home

๊ณต์ง€์‚ฌํ•ญ

์ธ๊ธฐ ๊ธ€

ํƒœ๊ทธ

  • Cypress
  • D3
  • react useRef
  • javascript pattern
  • swift
  • Design Pattern
  • vue cypress
  • vue storybook
  • svelte
  • React Native
  • Vue
  • TDD
  • react-component-slot
  • client only
  • vue3
  • apollo
  • jest
  • CSS
  • react
  • vue bdd
  • Nextjs
  • Kotlin
  • Vue test
  • storybook6
  • slot ํŒจํ„ด
  • vue tdd
  • Javascript
  • TypeScript
  • swift5
  • BDD

์ตœ๊ทผ ๋Œ“๊ธ€

์ตœ๊ทผ ๊ธ€

hELLO ยท Designed By ์ •์ƒ์šฐ.
eddie0329
Vue TDD - Component ํŽธ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”

๋‹จ์ถ•ํ‚ค

๋‚ด ๋ธ”๋กœ๊ทธ

๋‚ด ๋ธ”๋กœ๊ทธ - ๊ด€๋ฆฌ์ž ํ™ˆ ์ „ํ™˜
Q
Q
์ƒˆ ๊ธ€ ์“ฐ๊ธฐ
W
W

๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๊ธ€

๊ธ€ ์ˆ˜์ • (๊ถŒํ•œ ์žˆ๋Š” ๊ฒฝ์šฐ)
E
E
๋Œ“๊ธ€ ์˜์—ญ์œผ๋กœ ์ด๋™
C
C

๋ชจ๋“  ์˜์—ญ

์ด ํŽ˜์ด์ง€์˜ URL ๋ณต์‚ฌ
S
S
๋งจ ์œ„๋กœ ์ด๋™
T
T
ํ‹ฐ์Šคํ† ๋ฆฌ ํ™ˆ ์ด๋™
H
H
๋‹จ์ถ•ํ‚ค ์•ˆ๋‚ด
Shift + /
โ‡ง + /

* ๋‹จ์ถ•ํ‚ค๋Š” ํ•œ๊ธ€/์˜๋ฌธ ๋Œ€์†Œ๋ฌธ์ž๋กœ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ‹ฐ์Šคํ† ๋ฆฌ ๊ธฐ๋ณธ ๋„๋ฉ”์ธ์—์„œ๋งŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.