浅层游戏酶单元测试为整个应用程序树生成覆盖

时间:2018-05-03 22:22:40

标签: reactjs unit-testing code-coverage jestjs enzyme

我(为了演示目的)是一个非常简单的React组件:

import React, { Component } from 'react';

import { fetchUser, fetchNews } from '../../infrastructure/actions';

class Layout extends Component {
    render() {
        return (
            <div />
        );
    }
}
export default Layout;

和一个简单的Jest快照测试:

import React from 'react';
import { shallow } from 'enzyme';
import Layout from '../Layout';

describe('rendering', () => {
    it('should render valid snapshot when loading', () => {
        const jsx = (<Layout />);
        const element = shallow(jsx);
        expect(element).toMatchSnapshot();
    });
});

这里的相关行是

import { fetchUser, fetchNews } from '../../infrastructure/actions';

infrastructure/actions/index.js是一个充满Redux操作的桶文件,因此:

export { fetchNews, FETCH_NEWS } from './news/fetchNews';
export { fetchUser, FETCH_USER} from './user/fetchUser';
// ...etc

我的问题是,即使在浅层渲染组件中没有使用import语句中的任何内容,Jest的代码覆盖率报告也将infrastructure/actions/index.js文件中的每个模块视为已导入并执行,留下我一个无用的代码覆盖率报告,看起来像这样。

--------------------------------------------------|----------|----------|----------|----------|-------------------|
File                                              |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
--------------------------------------------------|----------|----------|----------|----------|-------------------|
All files                                         |    56.08 |    38.46 |     5.17 |    56.08 |                   |
 display/containers                               |      100 |      100 |      100 |      100 |                   |
  Layout.js                                       |      100 |      100 |      100 |      100 |                   |
 infrastructure/actions                           |      100 |      100 |      100 |      100 |                   |
  index.js                                        |      100 |      100 |      100 |      100 |                   |
 infrastructure/actions/characters                |       50 |        0 |        0 |       50 |                   |
  fetchCharacters.js                              |       50 |      100 |        0 |       50 |                 3 |
  fetchedCharactersFailure.js                     |       50 |      100 |        0 |       50 |                 3 |
  fetchedCharactersSuccess.js                     |       50 |      100 |        0 |       50 |                 3 |
  untrackCharacter.js                             |       50 |      100 |        0 |       50 |                 5 |
  untrackCharacterFailure.js                      |       50 |      100 |        0 |       50 |                 3 |
  untrackCharacterSuccess.js                      |       50 |      100 |        0 |       50 |                 3 |
  upsertCharacter.js                              |       50 |        0 |        0 |       50 |                 5 |
  upsertCharacterFailure.js                       |       50 |      100 |        0 |       50 |                 3 |
  upsertCharacterSuccess.js                       |       50 |      100 |        0 |       50 |                 3 |
 infrastructure/actions/help                      |       50 |      100 |        0 |       50 |                   |
  submitContactForm.js                            |       50 |      100 |        0 |       50 |                 5 |
  submitContactFormFailure.js                     |       50 |      100 |        0 |       50 |                 3 |
  submitContactFormSuccess.js                     |       50 |      100 |        0 |       50 |                 3 |
 infrastructure/actions/news                      |       50 |      100 |        0 |       50 |                   |
  fetchNews.js                                    |       50 |      100 |        0 |       50 |                 3 |
  fetchedNewsSuccess.js                           |       50 |      100 |        0 |       50 |                 3 |
 infrastructure/actions/public                    |       50 |        0 |        0 |       50 |                   |
  fetchPublicThreads.js                           |       50 |      100 |        0 |       50 |                 3 |
  fetchPublicViews.js                             |       50 |      100 |        0 |       50 |                 3 |
  fetchedPublicThreadsFailure.js                  |       50 |      100 |        0 |       50 |                 3 |
  fetchedPublicThreadsSuccess.js                  |       50 |      100 |        0 |       50 |                 3 |
  fetchedPublicViewsFailure.js                    |       50 |      100 |        0 |       50 |                 3 |
  fetchedPublicViewsSuccess.js                    |       50 |      100 |        0 |       50 |                 3 |
  untrackPublicView.js                            |       50 |      100 |        0 |       50 |                 5 |
  untrackPublicViewFailure.js                     |       50 |      100 |        0 |       50 |                 3 |
  untrackPublicViewSuccess.js                     |       50 |      100 |        0 |       50 |                 3 |
  upsertPublicView.js                             |       50 |        0 |        0 |       50 |                 5 |
  upsertPublicViewFailure.js                      |       50 |      100 |        0 |       50 |                 3 |
  upsertPublicViewSuccess.js                      |       50 |      100 |        0 |       50 |                 3 |
 infrastructure/actions/tags                      |       50 |      100 |        0 |       50 |                   |
  fetchTags.js                                    |       50 |      100 |        0 |       50 |                 3 |
  fetchedTagsSuccess.js                           |       50 |      100 |        0 |       50 |                 3 |
 infrastructure/actions/threads                   |       50 |        0 |        0 |       50 |                   |
  bulkUntrackThreads.js                           |       50 |      100 |        0 |       50 |                 5 |
  bulkUntrackThreadsFailure.js                    |       50 |      100 |        0 |       50 |                 3 |
  bulkUntrackThreadsSuccess.js                    |       50 |      100 |        0 |       50 |                 3 |
  bulkUpdateThreads.js                            |       50 |      100 |        0 |       50 |                 5 |
  bulkUpdateThreadsFailure.js                     |       50 |      100 |        0 |       50 |                 3 |
  bulkUpdateThreadsSuccess.js                     |       50 |      100 |        0 |       50 |                 3 |
  exportThreads.js                                |       50 |      100 |        0 |       50 |                 5 |
  exportThreadsFailure.js                         |       50 |      100 |        0 |       50 |                 3 |
  exportThreadsSuccess.js                         |       50 |      100 |        0 |       50 |                 3 |
  fetchActiveThreads.js                           |       50 |      100 |        0 |       50 |                 3 |
  fetchActiveThreadsStatus.js                     |       50 |      100 |        0 |       50 |                 3 |
  fetchArchivedThreads.js                         |       50 |      100 |        0 |       50 |                 3 |
  fetchedActiveThreadsFailure.js                  |       50 |      100 |        0 |       50 |                 3 |
  fetchedActiveThreadsStatusChunkFailure.js       |       50 |      100 |        0 |       50 |                 3 |
  fetchedActiveThreadsStatusChunkSuccess.js       |       50 |      100 |        0 |       50 |                 3 |
  fetchedActiveThreadsStatusFailure.js            |       50 |      100 |        0 |       50 |                 3 |
  fetchedActiveThreadsStatusSuccess.js            |       50 |      100 |        0 |       50 |                 3 |
  fetchedActiveThreadsSuccess.js                  |       50 |      100 |        0 |       50 |                 3 |
  fetchedArchivedThreadsFailure.js                |       50 |      100 |        0 |       50 |                 3 |
  fetchedArchivedThreadsSuccess.js                |       50 |      100 |        0 |       50 |                 3 |
  generateRandomThread.js                         |       50 |      100 |        0 |       50 |                 5 |
  generatedRandomThreadSuccess.js                 |       50 |      100 |        0 |       50 |                 3 |
  setFilteredTag.js                               |       50 |      100 |        0 |       50 |                 3 |
  untrackThread.js                                |       50 |      100 |        0 |       50 |                 5 |
  untrackThreadFailure.js                         |       50 |      100 |        0 |       50 |                 3 |
  untrackThreadSuccess.js                         |       50 |      100 |        0 |       50 |                 3 |
  upsertThread.js                                 |       50 |        0 |        0 |       50 |                 5 |
  upsertThreadFailure.js                          |       50 |      100 |        0 |       50 |                 3 |
  upsertThreadSuccess.js                          |       50 |      100 |        0 |       50 |                 3 |
 infrastructure/actions/ui                        |       50 |        0 |        0 |       50 |                   |
  closeBulkUntrackThreadsModal.js                 |       50 |      100 |        0 |       50 |                 3 |
  closeUntrackCharacterModal.js                   |       50 |      100 |        0 |       50 |                 3 |
  closeUntrackPublicViewModal.js                  |       50 |      100 |        0 |       50 |                 3 |
  closeUntrackThreadModal.js                      |       50 |      100 |        0 |       50 |                 3 |
  closeUpsertCharacterModal.js                    |       50 |      100 |        0 |       50 |                 3 |
  closeUpsertPublicViewModal.js                   |       50 |      100 |        0 |       50 |                 3 |
  closeUpsertThreadModal.js                       |       50 |      100 |        0 |       50 |                 3 |
  openBulkUntrackThreadsModal.js                  |       50 |      100 |        0 |       50 |                 3 |
  openUntrackCharacterModal.js                    |       50 |      100 |        0 |       50 |                 3 |
  openUntrackPublicViewModal.js                   |       50 |      100 |        0 |       50 |                 3 |
  openUntrackThreadModal.js                       |       50 |      100 |        0 |       50 |                 3 |
  openUpsertCharacterModal.js                     |       50 |        0 |        0 |       50 |                 5 |
  openUpsertPublicViewModal.js                    |       50 |        0 |        0 |       50 |                 5 |
  openUpsertThreadModal.js                        |       50 |        0 |        0 |       50 |                 5 |
  setActiveHelpTab.js                             |       50 |      100 |        0 |       50 |                 5 |
  setActiveSettingsTab.js                         |       50 |      100 |        0 |       50 |                 5 |
  setActiveToolsTab.js                            |       50 |      100 |        0 |       50 |                 5 |
  setMaintenanceModeOn.js                         |       50 |      100 |        0 |       50 |                 3 |
  toggleHeaderDropdown.js                         |       50 |      100 |        0 |       50 |                 5 |
  toggleMobileSidebar.js                          |       50 |      100 |        0 |       50 |                 5 |
  toggleNewsAside.js                              |       50 |      100 |        0 |       50 |                 5 |
  toggleSidebar.js                                |       50 |      100 |        0 |       50 |                 5 |
 infrastructure/actions/user                      |       50 |      100 |        0 |       50 |                   |
  fetchUser.js                                    |       50 |      100 |        0 |       50 |                 3 |
  fetchedUserFailure.js                           |       50 |      100 |        0 |       50 |                 3 |
  fetchedUserSuccess.js                           |       50 |      100 |        0 |       50 |                 3 |
  submitUserAccountInfo.js                        |       50 |      100 |        0 |       50 |                 5 |
  submitUserChangePassword.js                     |       50 |      100 |        0 |       50 |                 5 |
  submitUserForgotPassword.js                     |       50 |      100 |        0 |       50 |                 5 |
  submitUserLogin.js                              |       50 |      100 |        0 |       50 |                 5 |
  submitUserLogout.js                             |       50 |      100 |        0 |       50 |                 5 |
  submitUserRegistration.js                       |       50 |      100 |        0 |       50 |                 5 |
  submitUserResetPassword.js                      |       50 |      100 |        0 |       50 |                 5 |
  userAccountInfoFailure.js                       |       50 |      100 |        0 |       50 |                 3 |
  userAccountInfoSuccess.js                       |       50 |      100 |        0 |       50 |                 3 |
  userChangePasswordFailure.js                    |       50 |      100 |        0 |       50 |                 3 |
  userChangePasswordSuccess.js                    |       50 |      100 |        0 |       50 |                 3 |
  userForgotPasswordFailure.js                    |       50 |      100 |        0 |       50 |                 3 |
  userForgotPasswordSuccess.js                    |       50 |      100 |        0 |       50 |                 3 |
  userLoginFailure.js                             |       50 |      100 |        0 |       50 |                 3 |
  userLoginSuccess.js                             |       50 |      100 |        0 |       50 |                 3 |
  userRegistrationFailure.js                      |       50 |      100 |        0 |       50 |                 3 |
  userRegistrationSuccess.js                      |       50 |      100 |        0 |       50 |                 3 |
  userResetPasswordFailure.js                     |       50 |      100 |        0 |       50 |                 3 |
  userResetPasswordSuccess.js                     |       50 |      100 |        0 |       50 |                 3 |
 infrastructure/actions/userSettings              |       50 |      100 |        0 |       50 |                   |
  fetchUserSettings.js                            |       50 |      100 |        0 |       50 |                 3 |
  fetchedUserSettingsFailure.js                   |       50 |      100 |        0 |       50 |                 3 |
  fetchedUserSettingsSuccess.js                   |       50 |      100 |        0 |       50 |                 3 |
  setShowDashboardThreadDistribution.js           |       50 |      100 |        0 |       50 |                 5 |
  updateUserSettings.js                           |       50 |      100 |        0 |       50 |                 5 |
  updatedUserSettingsFailure.js                   |       50 |      100 |        0 |       50 |                 3 |
  updatedUserSettingsSuccess.js                   |       50 |      100 |        0 |       50 |                 3 |
 infrastructure/constants                         |      100 |      100 |      100 |      100 |                   |
  analytics.js                                    |      100 |      100 |      100 |      100 |                   |
 utility                                          |     62.5 |      100 |       50 |     62.5 |                   |
  testHelpers.js                                  |     62.5 |      100 |       50 |     62.5 |          12,13,16 |
--------------------------------------------------|----------|----------|----------|----------|-------------------|

毋庸置疑,这否定了代码覆盖率报告的目的,因为除了其中两个文件之外,这些文件都没有与被测试的组件相关 - 即使是那些文件,它们的代码也不应该通过这个测试来执行。

同样值得注意的是 - 在代码覆盖率报告的底部,它引用analytics.js,它实际上由infrastructure/actions/index.js的一个子文件导入,而不是由桶文件本身导入,这意味着覆盖范围以某种方式在依赖树中进一步传播。

只要删除导入操作的行,coverage文件就会立即再次自行运行并仅反映正在测试的组件。

如果我导入一个可能(可能)在布局中某处使用的组件,也会发生这种情况;我立即开始看到该组件及其子组件的覆盖指示一直向下,即使我只在我测试的组件中进行浅渲染。

在运行jest.mock()方法之前,我曾尝试使用shallow()来模拟这些导入,但它似乎没有对coverage输出产生任何影响。

所有这些让我相信我在设置我的测试环境时做错了什么;我对任何可能导致这种影响的指导表示感谢。

1 个答案:

答案 0 :(得分:0)

对于那些好奇的人,我做了一些挖掘,并意识到这实际上是预期的行为 - 默认情况下导入的文件在导入时执行,所以虽然导入的文件中没有任何函数被执行,但是他们被初始化仍然因为他们的进口而受到打击。

这个解决方案是使用Jest模拟来模拟被测系统使用的所有导入,作为测试初始化​​的一部分。我将此行添加到测试文件的底部(Jest在执行期间将其提升到测试的顶部):

jest.mock('../../../infrastructure/actions', () => ({}));

(即当导入调用actions/index.js时,则导入一个返回空对象的函数)。一切都恢复正常。