<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 編寫測試 由于你寫的大部分 Redux 代碼是函數,而且其中大部分是純函數,所以很好測,不需要模擬。 ## 準備工作 我們推薦使用 [Jest](https://jestjs.io/)) 作為測試引擎,需要注意的是 Jest 運行在 Node 環境中,因此你不能訪問 DOM。 ```bash npm install --save-dev jest ``` 如果想要和 [Babel](http://babeljs.io/) 一起使用,還需要安裝 `babel-jest` ```bash npm install --save-dev babel-jest ``` 并且在 `.babelrc` 中通過 [babel-preset-env](https://github.com/babel/babel/tree/master/packages/babel-preset-env) 來配置 ```javascript { "presets": ["@babel/preset-env"] } ``` 然后,在 `package.json` 中的 `scripts` 處添加相關的命令 ```json { ... "scripts": { ... "test": "jest", "test:watch": "npm test -- --watch" }, ... } ``` 執行 `npm test` 可以運行一次測試,執行 `npm run test:watch` 可以讓每當文件改變時自動執行測試。 ## 測試 Action Creators 在 Redux 中,action creators 是返回普通對象的函數,當我們測試 action creators 時,我們想要測試是否調用了正確的 action creator 以及是否返回了正確的 action。 ### 示例 ```js export function addTodo(text) { return { type: 'ADD_TODO', text } } ``` 可以這樣來測試: ```js import * as actions from '../../actions/TodoActions' import * as types from '../../constants/ActionTypes' ? describe('actions', () => { it('should create an action to add a todo', () => { const text = 'Finish docs' const expectedAction = { type: types.ADD_TODO, text } expect(actions.addTodo(text)).toEqual(expectedAction) }) }) ``` ## 測試異步 Action Creators 對于使用 [Redux-Thunk](https://github.com/reduxjs/redux-thunk) 或者其它中間件的異步 action Creator ,最好完全模擬 Redux store 來進行測試,可以通過使用 [redux-mock-store](https://github.com/dmitry-zaets/redux-mock-store) 來把中間件應用于模擬的 store,還可以使用 [fetch-mock](http://www.wheresrhys.co.uk/fetch-mock/)) 來模擬 HTTP 請求。 ### 示例 ```js import 'cross-fetch/polyfill' ? function fetchTodosRequest() { return { type: FETCH_TODOS_REQUEST } } ? function fetchTodosSuccess(body) { return { type: FETCH_TODOS_SUCCESS, body } } ? function fetchTodosFailure(ex) { return { type: FETCH_TODOS_FAILURE, ex } } ? export function fetchTodos() { return dispatch => { dispatch(fetchTodosRequest()) return fetch('http://example.com/todos') .then(res => res.json()) .then(body => dispatch(fetchTodosSuccess(body))) .catch(ex => dispatch(fetchTodosFailure(ex))) } } ``` 可以這樣來測試: ```js import configureMockStore from 'redux-mock-store' import thunk from 'redux-thunk' import * as actions from '../../actions/TodoActions' import * as types from '../../constants/ActionTypes' import fetchMock from 'fetch-mock' import expect from 'expect' // 可以使用任何測試庫 ? const middlewares = [thunk] const mockStore = configureMockStore(middlewares) ? describe('async actions', () => { afterEach(() => { fetchMock.reset() fetchMock.restore() }) ? it('creates FETCH_TODOS_SUCCESS when fetching todos has been done', () => { fetchMock .getOnce('/todos', { body: { todos: ['do something'] }, headers: { 'content-type': 'application/json' } }) ? ? const expectedActions = [ { type: types.FETCH_TODOS_REQUEST }, { type: types.FETCH_TODOS_SUCCESS, body: { todos: ['do something'] } } ] const store = mockStore({ todos: [] }) ? return store.dispatch(actions.fetchTodos()).then(() => { // return of async actions expect(store.getActions()).toEqual(expectedActions) }) }) }) ``` ## 測試 Reducers Reducer 把 action 應用到之前的 state,并返回新的 state。示例如下。 ### 示例 ```js import { ADD_TODO } from '../constants/ActionTypes' ? const initialState = [ { text: 'Use Redux', completed: false, id: 0 } ] ? export default function todos(state = initialState, action) { switch (action.type) { case ADD_TODO: return [ { id: state.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1, completed: false, text: action.text }, ...state ] ? default: return state } } ``` 可以這樣來測試: ```js import reducer from '../../reducers/todos' import * as types from '../../constants/ActionTypes' ? describe('todos reducer', () => { it('should return the initial state', () => { expect(reducer(undefined, {})).toEqual([ { text: 'Use Redux', completed: false, id: 0 } ]) }) ? it('should handle ADD_TODO', () => { expect( reducer([], { type: types.ADD_TODO, text: 'Run the tests' }) ).toEqual([ { text: 'Run the tests', completed: false, id: 0 } ]) ? expect( reducer( [ { text: 'Use Redux', completed: false, id: 0 } ], { type: types.ADD_TODO, text: 'Run the tests' } ) ).toEqual([ { text: 'Run the tests', completed: false, id: 1 }, { text: 'Use Redux', completed: false, id: 0 } ]) }) }) ``` ## 測試組件 React 組件有一個優點,它們通常很小且只依賴于傳入的 `props` ,因此測試起來很簡便。 首先,我們需要安裝 [Enzyme](http://airbnb.io/enzyme/) ,Enzyme 底層使用了 [React Test Utilities](https://reactjs.org/docs/test-utils.html) ,但是更方便,更具可讀性,更強大。 ```bash npm install —save-dev enzyme ``` 為了兼容 React 的版本,我們還需要安裝 Enzyme 適配器,Enzyme 提供了適配器用以兼容 `React16` ,`React 15.x`,`React 0.14.x`,`React 0.13.x`。如果你使用的是 React16,你可以使用下面的命令安裝相關依賴: ```bash npm install --save-dev enzyme-adapter-react-16 ``` 為了測試組件,我們創建了一個 `setup()` 輔助函數,用來把模擬過的(stubbed)回調函數當作 props 傳入,然后使用 ([React Shallow Rendering](https://reactjs.org/docs/test-utils.html#shallow-rendering)) 來渲染組件。這樣就可以依據 “是否調用了回調函數” 的斷言來寫獨立的測試。 ### 示例 ```js import React, { Component } from 'react' import PropTypes from 'prop-types' import TodoTextInput from './TodoTextInput' ? class Header extends Component { handleSave(text) { if (text.length !== 0) { this.props.addTodo(text) } } ? render() { return ( <header className="header"> <h1>todos</h1> <TodoTextInput newTodo={true} onSave={this.handleSave.bind(this)} placeholder="What needs to be done?" /> </header> ) } } ? Header.propTypes = { addTodo: PropTypes.func.isRequired } ? export default Header ``` 上面的組件可以這樣來測試: ```js import React from 'react' import Enzyme, { mount } from 'enzyme' import Adapter from 'enzyme-adapter-react-16'; import Header from '../../components/Header' ? Enzyme.configure({ adapter: new Adapter() }); ? function setup() { const props = { addTodo: jest.fn() } ? const enzymeWrapper = mount(<Header {...props} />) ? return { props, enzymeWrapper } } ? describe('components', () => { describe('Header', () => { it('should render self and subcomponents', () => { const { enzymeWrapper } = setup() ? expect(enzymeWrapper.find('header').hasClass('header')).toBe(true) ? expect(enzymeWrapper.find('h1').text()).toBe('todos') ? const todoInputProps = enzymeWrapper.find('TodoTextInput').props() expect(todoInputProps.newTodo).toBe(true) expect(todoInputProps.placeholder).toEqual('What needs to be done?') }) ? it('should call addTodo if length of text is greater than 0', () => { const { enzymeWrapper, props } = setup() const input = enzymeWrapper.find('TodoTextInput') input.props().onSave('') expect(props.addTodo.mock.calls.length).toBe(0) input.props().onSave('Use Redux') expect(props.addTodo.mock.calls.length).toBe(1) }) }) }) ``` ## 測試 connected 組件 如果你使用類似 [React redux](https://github.com/reduxjs/react-redux) 的庫,你可能會使用 [高階組件](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750),比如 [`connect()` ](https://github.com/reduxjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options)。可以讓你把 Redux state 注入到常規的 React 組件中。 考慮如下 `App` 組件 ```js import { connect } from 'react-redux' ? class App extends Component { /* ... */ } ? export default connect(mapStateToProps)(App) ``` 在單元測試中,通常會這樣導入 `App` 組件: ``` import App from './App' ``` 不過,上面這樣導入的是通過 `connect()` 方法返回的包裝組件,并非 `App` 組件本身,如果你想測試和 Redux 的整合,這很容易,通過 [`<Provider>`](https://github.com/reduxjs/react-redux/blob/master/docs/api.md#provider-store)包裹它后傳入用以單元測試的特殊 store 就可以了。但是有時候我們想測試的其實是不帶 Redux store 的組件的渲染。 為了測試 App 組件本身而不用處理裝飾器,我們推薦你導出未裝飾的組件: ```js import { connect } from 'react-redux' ? // 命名導出未連接的組件 (測試用) export class App extends Component { /* ... */ } ? // 默認導出已連接的組件 (app 用) export default connect(mapStateToProps)(App) ``` 由于默認導出的組件依舊是包裝過的組件,上面代碼中的導入依舊會生效,無須你更改已有的代碼。不過現在你可以通過下面這樣的辦法導入未裝飾的組件了: ```js import { App } from './App' ``` 如果你需要導入二者,可以按下面這樣做: ```js import ConnectedApp, { App } from './App' ``` 在 app 中,仍然正常地導入: ```js import App from './App' ``` 只在測試中使用命名導出。 > **混用 ES6 模塊和 CommonJS 的注意事項** > > 如果在應用代碼中使用 ES6,但在測試中使用 ES5,Babel 會通過其 [`interop`](https://old.babeljs.io/docs/plugins/#interop) 機制處理 ES6 的 `import` 和 CommonJS 的 `require` ,使得這兩種模式能一起使用,但其行為依舊有細微的區別。 如果在默認導出的附近增加另一個導出,將導致無法默認導出 `require('./App')`。此時,應代以 `require('./App').default` ## 對中間件的測試 中間件函數包裝了 Redux 中 `dispatch` 的行為,為了測試中間件的行為,我們需要模擬 `dispatch` 調用時的行為。 ### 示例 首先,我們需要創建一個中間件函數,下述代碼和 [redux-thunk](https://github.com/reduxjs/redux-thunk/blob/master/src/index.js) 類似 ```js const thunk = ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState) } ? return next(action) } ``` 我們需要創造一個假的 `getState`,`dispatch` 和 `next` 函數,我們可以使用 `jest.fn()` 來創建 stubs,你也可以使用 sinon 等測試框架 我們可以像 Redux 一樣來觸發函數 ```js const create = () => { const store = { getState: jest.fn(() => ({})), dispatch: jest.fn(), }; const next = jest.fn() ? const invoke = (action) => thunk(store)(next)(action) ? return {store, next, invoke} }; ``` 然后我們在適當的時機通過調用 `getState`,`dispatch`,`next`函數來測試中間件。 ```js it('passes through non-function action', () => { const { next, invoke } = create() const action = {type: 'TEST'} invoke(action) expect(next).toHaveBeenCalledWith(action) }) ? it('calls the function', () => { const { invoke } = create() const fn = jest.fn() invoke(fn) expect(fn).toHaveBeenCalled() }); ? it('passes dispatch and getState', () => { const { store, invoke } = create() invoke((dispatch, getState) => { dispatch('TEST DISPATCH') getState(); }) expect(store.dispatch).toHaveBeenCalledWith('TEST DISPATCH') expect(store.getState).toHaveBeenCalled() }); ``` 在一些情況下,你需要修改 `create` 函數來模擬不同的 `getState` 和 `next` 。 ## 詞匯表 - [Enzyme](http://airbnb.io/enzyme/): Enzyme 是一種用于 React 測試的 JavaScript 工具,它使得斷言、操作以及遍歷你的 React 組件的輸出變得更簡單。 - [React Test Utilities](https://reactjs.org/docs/test-utils.html) :React 提供的測試工具,被 Enzyme 使用 - [shallow renderer](http://airbnb.io/enzyme/docs/api/shallow.html): shallow renderer 使你可以實例化一個組件, 并有效地獲取其 `render` 方法的結果, 其渲染深度僅一層, 而非遞歸地將組件渲染為 DOM。 shallow renderer 對單元測試很有用, 你只要測試某個特定的組件,而不用管它的子組件。這也意味著,更改子組件不會影響到其父組件的測試。如果要測試一個組件和它所有的子組件,可以用 [`Enzyme's mount()`](http://airbnb.io/enzyme/docs/api/mount.html) 方法 ,這個方法會進行完全的 DOM 渲染。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看