前端测试

484 阅读3分钟

前端单元测试和e2e测试

一、单元测试

1.什么是单元测试?

  单元测试就是对代码中的最小单元进行测试,
  前端代码中的最小单元是什么?
  一个组件,一个按钮,一个函数,前端的组件太多了,所以没有必要对所有的单元都做测试。

2.可以测些什么?

 测没有I/O和UI依赖的工具函数,入参出参是否正确,

 测UI 表现  

 测试异步(异步请求回调)

3.测试框架、测试库

 1.测试框架  jest  

 2.测试库  enzyme    

   React的JavaScript测试工具,主要用于单元测试中 渲染和操作dom

   https://enzymejs.github.io/enzyme/

二、e2e测试

1.什么是e2e测试?

 end to end 端对端,也叫冒烟测试,
 在真实浏览器环境下,模拟用户的行为,也就是代替人工操作应用,去测试前端应用的流程。

2.可以测些什么?

 测整个页面的流程和表现

 测试需求是否正确完成

 模拟用户操作后,得到的是不是预期结果

3.测试框架、测试工具

1.测试框架 jest   

2.测试工具 puppeteer   

使用 chrome / chromium 作为浏览器环境运行应用,并且提供了非常语义化的 API 来描述业务逻辑

https://github.com/googlechrome/puppeteer

三、测试框架 jest

Facebook 的一套开源的 JavaScript 测试框架 ,集成了断言、JSDom、测试覆盖率报告功能。

单元测试 例:

1.测试dva reducers

测试reducers 中 changeStateValues

changeStateValues

changeStateValues(state, { payload }) {
    return {
      ...state,
      ...payload,
    };
  },

测试changeStateValues

import ContractManageModel from '@/pages/Personnel/ContractManage/model';

describe('test reducers', () => {
  const initState = {};
  it('changeStateValues', () => {
    const changeStateValues = ContractManageModel.reducers.changeStateValues;
    const payload = {
       testState: true,
    };
    const state = changeStateValues(initState, { payload });
    expect(state).toEqual({ ...payload });
  });
});

2.测试dva effects

测试effects 中 fetchList

fetchList

*fetchList({ payload }, { call, put }) {
      yield put({
        type: 'changeLoading',
        payload: true,
      });
      const res = yield call(getContractList, payload);
      if (res.code == 200) {
        yield put({
          type: 'changeStateValues',
          payload: {
            list: formatListData(_.get(res, 'data.list', [])),
          },
        });
        yield put({
          type: 'changePagination',
          payload: { total: _.get(res, 'data.allRows', 0) },
        });
      }
      yield put({
        type: 'changeLoading',
        payload: false,
      });
      return res;
    },

effect函数是个generator函数,generator中yield会暂停函数,需要手动next(),

dva中redux-saga 用来管理副作用,处理了generator函数继续执行,

测试时,就需要手动next了,

测试fetchList

describe('test effect', () => {
  it('fetchList', () => {
    const actionPayload = {
      payload: {
        currentPage: 1,
        pageRows: 10,
      },
    };
    const fetchList = ContractManageModel.effects.fetchList(actionPayload, { call, put });

    let next = fetchList.next();
    // put changeLoading
    expect(next.value).toEqual(
      put({
        type: 'changeLoading',
        payload: true,
      })
    );

    next = fetchList.next();
    // call
    expect(next.value).toEqual(call(getContractList, actionPayload.payload));

    // 模拟 res
    const res = {
      code: 200,
      data: { list: [], allRows: 0 },
    };
    next = fetchList.next(res);
    // put changeStateValues
    // 模拟formatListData
    const formatListDataMock = jest.fn().mockReturnValue(res.data.list);
    expect(next.value).toEqual(
      put({
        type: 'changeStateValues',
        payload: {
          list: formatListDataMock(),
        },
      })
    );

    next = fetchList.next();
    // put changePagination
    expect(next.value).toEqual(
      put({
        type: 'changePagination',
        payload: {
          total: res.data.allRows,
        },
      })
    );

    next = fetchList.next();
    // put changeLoading
    expect(next.value).toEqual(
      put({
        type: 'changeLoading',
        payload: false,
      })
    );

    const result = fetchList.next(res);
    expect(result.done).toEqual(true);
    expect(result.value).toEqual(res);
  });
});

3.测组件

浅渲染 dva包裹的组件

快照测试 npm i -D enzyme-to-json

describe('合同编辑快照测试', () => {
  const tree = shallow(<ContractEdit.WrappedComponent />);

  it('匹配快照', () => {
    expect(toJson(tree)).toMatchSnapshot();
  });
});

npm run test 后会生成一个快照文件,如果后面修改了dom,再跑测试会告诉哪里变动了,

完整渲染mount dva form 包裹的组件

import configureStore from 'redux-mock-store';

const mockStore = configureStore([]);
describe('合同编辑快照测试', () => {
  let store;
  let component;
  beforeEach(() => {
    store = mockStore({
      global: {},
    });
    const mockFn = jest.fn();
    const testForm = {
      getFieldDecorator: jest.fn(opts => c => c),
      getFieldValue: jest.fn(opts => c => c),
      validateFields: jest.fn(opts => c => c),
    };
    component = mount(<Mycomponent contractManage={{ stepFormValues: {} }} store={store} dispatch={mockFn} form={testForm} />);
  });

  it('匹配快照', () => {
    expect(toJson(component)).toMatchSnapshot();
  });
});

静态渲染render 只是把render中jsx渲染成html

异步测试

const handleStopPromise = handleStop => {
  return new Promise((resolve, reject) => {
    if (handleStop) {
      resolve(handleStop());
    }
  });
};
describe('测试异步', () => {
  it('handleStopPromise', () => {
    const mockFn = jest.fn().mockReturnValue(true);
    expect(handleStopPromise(mockFn)).resolves.toEqual(true);
  });
});