【问题标题】:Can't unit test redux-saga with selector function using Jest无法使用 Jest 对带有选择器功能的 redux-saga 进行单元测试
【发布时间】:2020-03-05 16:51:54
【问题描述】:

问题说明:

我想使用 Jest 对 redux-saga 进行单元测试。我正在按照 redux-saga 文档中提供的示例中描述的方式执行此操作:https://redux-saga.js.org/docs/advanced/Testing.html

在我的 Saga 中,我调用了一个选择器函数 selectSet,它从应用商店返回一个特定的对象:

export const selectSet = state => state.setStore.set

在我的传奇中,我试图产生这个选择器函数:

import { put, select } from 'redux-saga/effects'
import { selectSet } from '../selectors'

export function* getSet() {
  try {
    const set = yield select(selectSet)
    yield put({ type: 'SET_SUCCESS', payload: { set } })
  } catch (error) {
    yield put({ type: 'SET_ERROR', payload: { error } })
  }
}

在我的测试中,没有有效的应用商店,所以我必须模拟该函数以返回预期的对象:

import assert from 'assert'
import * as AppRoutines from './AppRoutines'
import { put, select } from 'redux-saga/effects'

describe('getSet()', () => {
    it('should trigger an action type "SET_SUCCESS" with a payload containing a valid set', () => {
        const generator = AppRoutines.getSet()

        const set = {
          id: 1,
          slots: [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }],
        }

        const selectSet = jest.fn()
        selectSet.mockReturnValue(set)

        // Saga step 1
        const actualFirst = generator.next().value
        const expectedFirst = select(selectSet)

        assert.deepEqual(
          actualFirst,
          expectedFirst,
          'it should retreive a valid set from the store using the selectSet selector'
        )
    })
})

但是 - 如果我断言 saga 使用 deepEqual 和我的模拟函数返回特定的生成器值,它希望我的选择器函数具有原始的 selectSet 构造函数。但由于我用 jest.fn() 模拟函数,因此构造函数实际上等于 mockConstructor - 这使我的测试失败:

Expected value to deeply equal to:
    {"@@redux-saga/IO": true, "SELECT": {"args": Array [], "selector": [Function mockConstructor]}}
Received:
    {"@@redux-saga/IO": true, "SELECT": {"args": Array [], "selector": [Function selectSet]}}

问题:我怎样才能使 assert.deepEqual 包含一个模拟函数而不冲突的构造函数类型?

替代问题:有没有办法让我的断言期待 mockConstructor 而不是实际的 selectSet 构造函数?

【问题讨论】:

    标签: javascript unit-testing react-redux jestjs redux-saga


    【解决方案1】:

    您根本不需要模拟选择器,因为在这种性质的 saga 测试中,选择器永远不会被实际调用,而是您正在测试为 redux saga 中间件创建的声明性指令以执行操作,如下所示你期待

    这是 saga 将创建 {"@@redux-saga/IO": true, "SELECT": {"args": Array [], "selector": [Function selectSet]}} 的指令,但由于在此测试场景期间未运行中间件,selectSelect 将永远不会真正被调用

    如果您需要模拟选择器为您的操作返回的结果,那么您可以通过将模拟数据传递到下一步来实现...

        const set = {
          id: 1,
          slots: [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }],
        }
    
        // Saga step 1
        const firstYield = generator.next().value
        assertDeepEqual(firstYield, select(selectSet))
    
        // Step 2 - successful so dispatch action
        // mock data from the previous yield by passing into this step via `next(stubbedYieldedData)`
        const secondYield = generator.next(set).value
        assertDeepEqual(secondYield, put({type: 'SET_SUCCESS', payload: {set} }))
    

    【讨论】:

    • 非常感谢@alechill。你真的拯救了我的一天。
    【解决方案2】:

    我们可以通过下面的假商店中的模拟商店。下面是示例选择器和生成器函数及其测试。

    选择器

    const authSelector = (state) => state.authReducer || initialState;
    

    传奇生成器函数

    export function* getAuthToken(action) {
      try {
        const authToken = yield select(makeSelectAuthToken());
      } catch (errObj) {}
    }
    

    测试用例

        import { runSaga } from 'redux-saga'
    
        const dispatchedActions = [];
    
        const fakeStore = {
            getState: () => ({ authReducer: { auth: 'test' } }),
            dispatch: (action) => dispatchedActions.push(action)
          }
    
         await runSaga(fakeStore, getAuthToken, {
            payload: {}
         }).done;
    
    expected case you can write here below this
    

    【讨论】:

      猜你喜欢
      • 2017-04-14
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-07
      • 2017-01-17
      相关资源
      最近更新 更多