Karma 및 Webpack을 사용하여 React 및 Flux 애플리케이션 테스트

반응 플럭스
Rescale에서는 다음을 사용하고 있었습니다. 농담 React 및 Flux 애플리케이션을 테스트하기 위한 Facebook의 프레임워크입니다. Jest는 Jest와 유사한 API를 사용하여 시작하기 쉬운 테스트 프레임워크입니다. 재스민 속, 그러나 CommonJS 모듈을 자동으로 조롱하는 기능이 포함되어 있습니다. 그러나 오픈 소스 커뮤니티의 많은 개발자처럼 유명한, 우리는 중요하지 않은 테스트 스위트를 실행할 때 Jest가 견딜 수 없을 정도로 느려질 수 있다는 것을 발견했습니다. 약 60개의 테스트 케이스로 구성된 테스트 스위트의 경우 완료하는 데 10초 이상이 걸립니다! 이 기사에서는 우리가 어떻게 포기했는지 설명합니다. 농담 에 찬성하여 , 웹팩재스민 속. 새로운 설정에서 실행되는 동일한 테스트 모음은 초기 Webpack 번들링 이후 PhantomJS에서 실행되는 데 200ms도 채 걸리지 않습니다.
테스트 설정은 이 문서에 설명된 내용을 기반으로 합니다. Karma 및 Webpack을 사용하여 ReactJS 구성 요소 테스트. Karma와 Webpack에 익숙하지 않다면 이 글을 읽어보세요. 요약하자면, 이 설정은 karma-webpack을 사용하여 모든 테스트를 Karma가 브라우저에서 로드하고 실행하는 단일 파일로 묶습니다. 이를 위해 필요한 npm 패키지는 다음과 같습니다.

  • 카르마클리
  • 카르마-자스민
  • 카르마-phantomjs-런처
  • 카르마 웹팩
  • 재스민 향수
  • 웹팩
  • core-js(ES5 shim용)
  • babel-loader (ES6에서 ES5로의 변환용)

Karma 구성 파일인 karma.conf.js는 다음과 같아야 합니다.

module.exports = function(config) { config.set({ 브라우저: ['PhantomJS'], 파일: [ { 패턴: 'tests.webpack.js', watch: false }, ], 프레임워크: ['jasmine'] , 전처리기: { 'tests.webpack.js': ['webpack'], }, 보고자: ['dots'], SingleRun: true, webpack: { 모듈: { 로더: [ { test: /\.jsx?$ /, 제외: /node_modules/, 로더: 'babel-loader' }, ], }, watch: true, }, webpackServer: { noInfo: true, }, }); };

그리고 테스트 스위트 Webpack 번들인 test.webpack.js의 진입점은 다음과 같아야 합니다.

// Function.prototype.bind, Object.prototype.keys 등에 대한 ES5 shim require('core-js/es5'); // ./src/js를 애플리케이션 코드의 디렉터리로 바꾸고 // 파일 이름 regexp가 테스트 파일과 일치하는지 확인하세요. var context = require.context('./src/js', true, /-test\.js$/); context.keys().forEach(컨텍스트);

다음은 구성 요소 ./src/js/comComponents/MemberList.jsx를 테스트하는 ./src/js/comComponents/__tests__/MemberList-test.js에 있는 샘플 테스트입니다.

var React = require('반응'); var TestUtils = require('react/lib/ReactTestUtils'); var MemberList = require('../MemberList.jsx'); explain('MemberList', () => { it('renders', () => { var element = TestUtils.renderIntoDocument(); Expect(element).toBeTruthy(); }); });

React 구성 요소를 테스트하는 데는 모두 훌륭하지만 Flux 애플리케이션, 특히 Flux Store를 테스트하려면 좀 더 많은 설정이 필요합니다.

Flux 저장소 테스트

Flux 저장소의 문제점은 저장소가 일반적으로 상태가 있는 싱글톤이라는 것입니다. 상태가 있는 싱글톤 테스트 간에 상태가 지속되기 때문에 테스트하기 가장 나쁜 것 중 하나일 수 있습니다. 애플리케이션의 많은 부분이 테스트 스위트 전체에서 스토어와 상호 작용할 때 스토어 상태를 예측하기가 어려워집니다. 각 테스트 사례 전에 저장소 상태를 재설정하는 몇 가지 방법을 구현할 수 있다고 생각할 수도 있지만 모든 저장소에 대해 이 작업을 수행하는 것은 유지 관리에 있어서 악몽이며 오류가 발생하기 매우 쉽습니다.
Jest는 자체 환경에서 모든 테스트 케이스를 실행하여 이 문제를 해결합니다. 즉, 테스트 케이스에 모듈이 필요할 때 가져온 모듈은 새로운 인스턴스입니다. 이것이 바로 매장을 테스트할 때 우리가 원하는 동작입니다.
Webpack을 사용하면 각 테스트 케이스 전에 require 캐시를 지워 require 호출이 모듈의 새로운 인스턴스를 로드하도록 할 수 있습니다. 최적화로서 우리는 필수 캐시에서 React와 같은 타사 모듈을 제거하고 싶지 않습니다. 그렇게 하면 테스트 스위트의 속도가 크게 느려질 것이며 어쨌든 해당 타사 모듈 중 어느 것도 상태가 있는 싱글톤이 되어서는 안 됩니다. 다음과 같이 test.webpack.js 파일에서 각 테스트 전에 캐시 무효화를 추가할 수 있습니다.

// 프로젝트의 모듈을 동적으로 요구할 수 있도록 // Webpack 요구 컨텍스트를 생성합니다. 이 컨텍스트에서 테스트 파일을 제외합니다. var projectContext = require.context('./src/js', true, /^((?!__tests__).)*.jsx?$/); // Webpack이 모듈을 추적하는 데 사용하는 모듈 ID를 추출합니다. var projectModuleIds = projectContext.keys().map(module => String(projectContext.resolve(module))); beforeEach(() => { // 각 테스트 사례 전에 필수 캐시에서 모듈을 제거합니다. projectModuleIds.forEach(id => delete require.cache[id]); });

이것이 필수 캐시를 파괴하는 전부입니다. 이제 모듈은 각 테스트 케이스 내에 캐시되지만 그 사이에 있지는 않습니다. 저장소, 작업 및 디스패처는 모두 테스트 간에 격리됩니다.

작업/저장 경계 테스트

우리는 사용 환류 우리 프로젝트 중 하나에 대한 Flux 구현이며 Actions는 거의 Stores용 공개 API입니다. 그러나 작업을 트리거하는 것은 비동기 작업이므로 테스트에서 비동기를 제어할 수 있는 방법이 필요합니다. 이는 기본 setTimeout 및 setInterval 함수를 모의하고 수동으로 발전시키는 기능을 제공하는 테스트 프레임워크 또는 라이브러리를 사용하면 쉬워야 합니다. 다음은 Jasmine을 사용하여 Action/Store 경계를 테스트하는 예입니다.

explain('MemberStore', () => { var MemberActions; var MemberStore; beforeEach(() => { jasmine.clock().install(); // 내장 타이머 모의 MemberActions = require('../ ../actions/MemberActions'); MemberStore = require('../MemberStore'); }); afterEach(() => { jasmine.clock().uninstall(); }); it('다음 경우 멤버를 저장합니다. received', () => { MemberAction.memberReceived({ name: 'Baz Fu' }); jasmine.clock().tick(); // 시계를 다음 틱으로 전진합니다. Expect(MemberStore.getAll().first ().get('이름')).toBe('바즈 푸'); }); });

모듈의 종속성 모의

우리가 모의하려는 다른 모듈에 종속된 모듈을 테스트하고 싶다고 가정해 보겠습니다. 한 가지 예는 다음과 같은 일부 http 모듈에 의존하는 API 모듈을 테스트하려는 것입니다. 액시 오스. Jest.setMock(moduleName, moduleExports) API 또는 자동 모의 기능을 사용하여 모의 항목을 쉽게 지정할 수 있기 때문에 Jest가 빛나는 곳입니다.
Jest 외부에서 이를 달성하는 한 가지 방법은 다음을 사용하는 것입니다. 다시 연결하다 그리고 웹팩 버전 웹팩 재연결. Rewire는 모듈의 개인 변수를 변경하는 데 사용할 수 있습니다. 예를 들어 api.js 모듈 내에서 axios 모듈을 조롱하려면 다음과 같이 작성할 수 있습니다.

// api.js var axios = require('axios'); var API = { doSomething() { axios.get('https://someurl/'); }, }; 모듈.수출 = API; // 일부 테스트에서 var API = rewire('../api'); API.__set__('axios', mockAxios);

또 다른 옵션은 Webpack의 필수 캐시를 다시 한 번 조작하는 것입니다.

require('축'); // 모듈이 로드되고 캐시되었는지 확인합니다. require.cache[require.resolve('axios')].exports = mockAxios;

다시 연결하는 것보다 이 방법의 이점은 우리가 다시 연결한 모듈뿐만 아니라 require('axios')에 대한 모든 호출이 조롱된다는 것입니다.
참고: http 요청 라이브러리를 조롱하는 것은 아마도 나쁜 예일 것입니다. 이를 위해서는 다음과 같은 것을 사용해야합니다 재스민-아약스 대신에, 당신은 아이디어를 얻습니다.

폐회사

Jest보다 Karma 및 Webpack을 사용하여 React 및 Flux 애플리케이션 테스트 스위트 실행 속도가 약 50배 향상되었습니다. 그러나 Jest에 비해 설정하는 데 약간 더 많은 지식과 노력이 필요하며 모듈의 종속성을 조롱하는 것은 쉽지 않습니다. Jest는 설정이 쉽기 때문에 정말 좋습니다. 하지만 너무 느리다는 점은 우리에게는 딜 브레이커이며, 문제가 해결될지는 알 수 없습니다. 그 동안 현재 설정을 통해 효과적으로 TDD를 수행할 수 있습니다.

비슷한 게시물