Vuex 테스트

1 개요[ | ]

Vuex Testing
Vuex 테스트, Vuex 테스팅
  • Vuex에서 단위 테스트를 하고자 하는 주요 부분은 변이와 액션이다.

2 변이 테스트[ | ]

  • 변이 테스트는 매우 간단하다.
  • 왜냐하면 변이는 전달인자에 완전히 의존하는 함수이기 때문이다.
  • 한 가지 트릭은 ES2015 모듈을 사용하면서 변이를 store.js 파일에 넣으면, 기본 export와 함께 변이를 지명 export로 내보낼 수 있다는 것이다.
const state = { ... }

// 변이를 지명 export로 내보낸다.
export const mutations = { ... }

export default new Vuex.Store({
  state,
  mutations
})

Mocha + Chai를 사용하여 변이를 테스트하는 예시 (원하는 프레임워크/assertion 라이브러리를 사용할 수 있다.)

// mutations.js
export const mutations = {
  increment: state => state.count++
}
// mutations.spec.js
import { expect } from 'chai'
import { mutations } from './store'

// 변이(mutations) 해체 할당
const { increment } = mutations

describe('mutations', () => {
  it('INCREMENT', () => {
    // mock state
    const state = { count: 0 }
    // 변이 적용
    increment(state)
    // 결과 확인
    expect(state.count).to.equal(1)
  })
})

3 액션 테스트[ | ]

  • 액션은 외부 API를 호출할 수 있으므로 약간 까다롭다.
  • 액션을 테스트할 때는 어느 정도 모조작업(mocking)을 해야 한다.
  • 예를 들어, API 호출을 서비스로 추상화하고 테스트 내에 그 서비스를 모조(mock)로 만들 수 있다.
  • 의존성을 쉽게 모조하고 테스트 파일들을 번들링하기 위해 webpack과 inject-loader를 사용할 수 있다.

비동기 액션 테스트 예시:

// actions.js
import shop from '../api/shop'

export const getAllProducts = ({ commit }) => {
  commit('REQUEST_PRODUCTS')
  shop.getProducts(products => {
    commit('RECEIVE_PRODUCTS', products)
  })
}
// actions.spec.js

// use require syntax for inline loaders.
// with inject-loader, this returns a module factory
// that allows us to inject mocked dependencies.
import { expect } from 'chai'
const actionsInjector = require('inject-loader!./actions')

// create the module with our mocks
const actions = actionsInjector({
  '../api/shop': {
    getProducts (cb) {
      setTimeout(() => {
        cb([ /* mocked response */ ])
      }, 100)
    }
  }
})

// helper for testing action with expected mutations
const testAction = (action, payload, state, expectedMutations, done) => {
  let count = 0

  // mock commit
  const commit = (type, payload) => {
    const mutation = expectedMutations[count]

    try {
      expect(type).to.equal(mutation.type)
      expect(payload).to.deep.equal(mutation.payload)
    } catch (error) {
      done(error)
    }

    count++
    if (count >= expectedMutations.length) {
      done()
    }
  }

  // call the action with mocked store and arguments
  action({ commit, state }, payload)

  // check if no mutations should have been dispatched
  if (expectedMutations.length === 0) {
    expect(count).to.equal(0)
    done()
  }
}

describe('actions', () => {
  it('getAllProducts', done => {
    testAction(actions.getAllProducts, null, {}, [
      { type: 'REQUEST_PRODUCTS' },
      { type: 'RECEIVE_PRODUCTS', payload: { /* mocked response */ } }
    ], done)
  })
})
  • 사용자의 테스팅 환경에서 스파이(예: Sinon.JS)를 사용할 수 있다면, testAction 헬퍼 대신에 그것을 사용할 수 있다.
describe('actions', () => {
  it('getAllProducts', () => {
    const commit = sinon.spy()
    const state = {}
    
    actions.getAllProducts({ commit, state })
    
    expect(commit.args).to.deep.equal([
      ['REQUEST_PRODUCTS'],
      ['RECEIVE_PRODUCTS', { /* mocked response */ }]
    ])
  })
})

4 게터 테스트[ | ]

  • 게터(getter)에 복잡한 연산이 있다면, 테스트를 해볼만하다.
  • 게타 테스트는 변이 테스트처럼 매우 간단하다.

getter 테스트 예시:

// getters.js
export const getters = {
  filteredProducts (state, { filterCategory }) {
    return state.products.filter(product => {
      return product.category === filterCategory
    })
  }
}
// getters.spec.js
import { expect } from 'chai'
import { getters } from './getters'

describe('getters', () => {
  it('filteredProducts', () => {
    // mock state
    const state = {
      products: [
        { id: 1, title: 'Apple', category: 'fruit' },
        { id: 2, title: 'Orange', category: 'fruit' },
        { id: 3, title: 'Carrot', category: 'vegetable' }
      ]
    }
    // mock getter
    const filterCategory = 'fruit'

    // get the result from the getter
    const result = getters.filteredProducts(state, { filterCategory })

    // assert the result
    expect(result).to.deep.equal([
      { id: 1, title: 'Apple', category: 'fruit' },
      { id: 2, title: 'Orange', category: 'fruit' }
    ])
  })
})

5 테스트 실행[ | ]

  • 변이와 액션이 적절히 작성되었다면, 적절한 목작업(mocking) 후에 테스트가 브라우저 API에 직접적인 의존성이 없어야 한다.
  • 따라서 webpack으로 테스트들을 간단히 번들로 묶고 Node에서 직접 실행할 수 있다.
  • 또는, mocha-loader나 Karma + karma-webpack을 사용하여 실제 브라우저에서 테스트를 실행할 수 있다.

5.1 Node에서 실행[ | ]

다음과 같이 webpack 설정을 작성한다 ( 적절한 .babelrc 필요 )

// webpack.config.js
module.exports = {
  entry: './test.js',
  output: {
    path: __dirname,
    filename: 'test-bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      }
    ]
  }
}

그런 다음:

webpack
mocha test-bundle.js

5.2 브라우저에서 실행[ | ]

  1. mocha-loader 설치
  2. 위의 webpack 설정에서 entry'mocha!babel!./test.js'로 변경
  3. 설정을 적용하여 webpack-dev-server 실행
  4. localhost:8080/webpack-dev-server/test-bundle로 이동

5.3 Karma + karma-webpack으로 브라우저에서 실행[ | ]

6 참고[ | ]

문서 댓글 ({{ doc_comments.length }})
{{ comment.name }} {{ comment.created | snstime }}