【问题标题】:How can i create fake functions to test the components?如何创建假函数来测试组件?
【发布时间】:2022-02-11 02:17:38
【问题描述】:

我必须测试我的组件,但该组件有一个功能,它可以工作,这个功能需要一个关键的环境,

我的函数有一个 onMounted 函数

 onMounted(async () => {

    const available = await getAvailableBills()

实现如下:

export const getAvailableBills = async () => {
  try {
    const bill = `${process.env.VAR_ENV}`

我收到此错误:

错误:提供的地址 {VAR_ENV} 无效

但我认为我不需要执行真正的功能,我想在我的测试中创建假功能

import { shallowMount } from '@vue/test-utils'
import { createApp } from 'vue'
import { createStore } from 'vuex'
import App from '@/components/tables'

const store = createStore({
  state() {
    return {
      user: {},
    }
  },
  mutations: {},
})

let wrapper
const app = createApp(App)
app.use(store)
beforeEach(() => {
  wrapper = shallowMount(App, {
    propsData: {
      whitelist: [1,2,3],
    },
    global: {
      plugins: [store],
    },
  })
})

describe('Tables', () => {
  it('test 1', () => {
    expect(wrapper.props().list).toEqual([1,2,3])
  })
})

【问题讨论】:

    标签: vue.js unit-testing jestjs


    【解决方案1】:

    你必须模拟它。你好像在开玩笑。您可以使用jest.spyOn 方法模拟特定对象,或使用jest.mock 模拟整个文件。

    例如,如果你有

    src /
    - app.js
    - app.spec.js
    - services /
    --- bills.js
    

    在您的src/app.spec.js 中,如果您导出的函数getAvailableBillssrc/services/bills.js 中,请执行以下操作:

    import { shallowMount } from '@vue/test-utils'
    import { createApp } from 'vue'
    import { createStore } from 'vuex'
    import App from '@/components/tables'
    
    import { getAvailableBills } from './services/bills'
    jest.mock('./services/bills', {
      getAvailableBills: jest.fn().mockResolvedValue({ bills: ['...'] }) // you can mock the response directly here for the whole file
    })
    
    getAvailableBills.mockResolvedValue({ bills: ['...'] }) // or you can mock the response when you need to mock it
    
    const store = createStore({
      state() {
        return {
          user: {},
        }
      },
      mutations: {},
    })
    
    let wrapper
    const app = createApp(App)
    app.use(store)
    beforeEach(() => {
      wrapper = shallowMount(App, {
        propsData: {
          whitelist: [1,2,3],
        },
        global: {
          plugins: [store],
        },
      })
    })
    
    describe('Tables', () => {
      it('test 1', () => {
        expect(wrapper.props().list).toEqual([1,2,3])
      })
    })
    

    请注意,我使用 mockResolvedValue 是因为它返回一个 Promise(异步方法),但如果它返回一个直接值而不是一个 Promise,请使用 mockReturnValue。您还可以在需要时使用 mockResolvedValueOncemockReturnValueOnce 模拟一次,或者使用 mockRejectedValue 模拟被拒绝的承诺。

    顺便说一句,您最好将测试封装在 describe 中,它可以避免一些错误,并且它使测试更具可读性和可写性。您还应该在 beforeAll / beforeEach 方法中模拟一次,以便在需要时进行多次测试。

    如果需要,您还可以添加一个设置文件,在其中实例化 jest.config 中的假 env 值。这不是重点,但有一天它可能会对你有所帮助。

    【讨论】:

      【解决方案2】:

      如果您尝试替换组件的函数/方法,简短的回答是:您不这样做!

      切勿在测试中替换组件的某些部分。在您对组件进行更改后,这些测试用于检查您的组件现在和将来是否会失败。如果您将来引入了重大更改,但测试替换了您引入更改的部分/方法,您的测试将如何知道应用程序已损坏?


      测试时需要遵循一些重要原则:

      1. 请勿修改您的组件以使其通过测试。仅对其进行修改以解决在测试期间发现的实际问题。
      2. 在测试期间切勿更换组件的部件。您可以(并且应该)做的是模拟任何外部的东西,用功能/模块替换这些部分,执行您期望这些部分在实时环境中执行的操作1。模拟的要点是:
        jest.mock('some-module', () => jest.fn().mockImplementation(() => yourMock )).
        完整文档here.
        模拟需要在您的测试调用 import Something from 'some-module' 之前进行。
      3. 仅测试组件的输入/输出。不要测试您的组件是如何工作的(也称为内部实现)(这允许您在以后的某个时间重构它而不会破坏测试,只要您的组件仍然按预期为每个提供的输入输出)。
        也不要测试外部东西是否有效。您的测试与此无关。外部的东西有自己的测试,通常已经测试过了。这就是您依赖它的原因。

      因此,在您的情况下,您希望在测试期间修改 process.env。唯一的问题是 process.env 是全局的,如果您对其进行更改,这些更改将在您的测试结束后持续存在,除非您将所有内容更改回开始测试时的状态。

      最重要的是,您必须在每次测试之前调用jest.resetModules(),以清除 jest 缓存(默认情况下,jest 缓存,因此它运行测试更快)。

      这是一个如何使用受控process.env 进行测试的示例。这应该消除了替换组件方法的需要:

      describe('SomeComponent', () => {
        const REAL_ENV = process.env;
      
        beforeEach(() => {
          jest.resetModules();
          process.env = { ...process.env }; // copy, for your test
        });
      
        afterAll(() => {
          process.env = REAL_ENV; // restore initial values
        });
      
        it('should do stuff depending on process.env', () => {
          process.env.FOO = 'bar';
      
          wrapper = shallowMount(/*...*/);
          expect(/* wrapper to do stuff...*/)
        })
      });
      

      使用受控process.env 值进行测试需要在测试内部进行浅层安装,而不是在beforeAll 中进行典型的浅层安装,我通常会创建两个单独的测试套件:一个用于正常测试,一个用于beforeAll 中的浅层安装,另一个对于特殊测试,在浅层安装之前设置环境变量:

      describe('SomeComponent - normal tests', () => {
        let wrapper;
        beforeEach(() => {
          wrapper = shallowMount(/*...*/)
        });
        it('should do stuff', () => {
          // component here has already been shallowMounted
        })
      });
      
      describe('SomeCompoent - process.env tests', () => {
        const REAL_ENV = process.env;
        let wrapper;
      
        beforeEach(/* ... */); // replace process.env
        afterEach(/* ... */); // restore process.env
      
        it('Does stuff with FOO = "bar"', () => {
          process.env.FOO = 'bar';
          wrapper = shallowMount(/* ... */);
          expect(/* wrapper to do stuff when process.env.FOO is 'bar' */)
        })
      
        it('Does stuff with FOO = "baz"', () => {
          process.env.FOO = 'baz';
          wrapper = shallowMount(/* ... */);
          expect(/* wrapper to do stuff when process.env.FOO is 'baz' */)
        })
      })
      

      1 例如,您不想在测试中使用 axios。您不想测试本地计算机是否已连接到 Internet,或者您的应用程序调用的服务器是否实际启动并运行。您想要一个 axios 的替代品,它可以在不进行实际调用的情况下执行 axios 正在做的事情,从而允许您控制返回的响应和错误,从而测试您的组件在从 axios 接收响应/错误时做出正确的调用并按预期运行。

      【讨论】:

      • 这些功能是ntfs web 3的,我可以花gas,我应该更换功能吗?
      • @signup,我不明白这个问题,抱歉。您可以用jest.mock('some-module', () => jest.fn().mockImplementation(() => yourMock)) 替换任何导入。见docs。请注意,必须在组件/测试实际调用 import stuff from 'some-module' 之前进行模拟。
      • 我仍然遇到一些错误,stackoverflow.com/questions/71059815/…
      猜你喜欢
      • 1970-01-01
      • 2016-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-24
      • 1970-01-01
      • 2019-12-09
      相关资源
      最近更新 更多