mocha.js로 여러 파일의 테스트 결합


88

다음과 같이 여러 파일의 모든 테스트를 하나의 파일에 결합하려고합니다.

  describe('Controllers', function() {
    describe('messages.js', function() {
      require('./controllertests/messages').test(options);
    })
    describe('users.js', function() {
      require('./controllertests/users').test(options);
    })
  })

나는 이것이 테스트에 참여하는 가장 좋은 방법이 아니라고 확신합니다.이 작업을 수행하는 방법에 대한 예제를 찾는 데 어려움이 있습니다.


1
궁금한 점은 왜 테스트를 하나의 파일로 결합해야합니까?
thgaskell 2014

2
지역 변수와 조직을 공유하기 위해
coiso

질문에 테스트를 포함하는 것이 더 합리적 일 수 있습니다. (단위 테스트와는 반대로) 통합 테스트를 선호하는 것 같습니다. 일반적으로 테스트간에 변수를 공유 할 필요가 없습니다.
thgaskell

2
그리고 큰 문제는 1 개의 huuuuge 파일보다 20 개의 파일을 선호한다는 것입니다
coiso

2
또한 Mocha가 개념으로 스위트를 처리하는 방법을 살펴보면 전체 테스트 디렉토리를 계속 실행할 .only()수있는 것이 유용 할 수 있습니다 describe.only(). 그것이 나를 여기로 데려온 것입니다.
크리스

답변:


114

여러 모듈을 포함 할 경우 당신의 describe당신이 당신의 질문을하고있는 같은 계층 구조를, 무슨 일을 꽤 많이 그것은 당신이 모카에 대한 사용자 정의 테스트 로더를 쓰고 싶어하지 않는 한. 커스텀 로더를 작성하는 것은 이미 가지고있는 것보다 코드를 더 명확하게 만들거나 쉽지 않습니다.

다음은 몇 가지 사항을 변경하는 방법의 예입니다. test이 예에서 하위 디렉토리는 다음과 같이 구성되어 있습니다 :

.
└── test
    ├── a
    │   └── a.js
    ├── b
    │   └── b.js
    ├── common.js
    └── top.js

top.js:

function importTest(name, path) {
    describe(name, function () {
        require(path);
    });
}

var common = require("./common");

describe("top", function () {
    beforeEach(function () {
       console.log("running something before each test");
    });
    importTest("a", './a/a');
    importTest("b", './b/b');
    after(function () {
        console.log("after all tests");
    });
});

importTest기능은 describe(... require...매번 전체 내용을 다시 입력하지 않고도 여러 모듈을 가져 오는 반복을 처리 할 수있는 방법을 보여주는 것입니다. common모듈은 사용자가 테스트 스위트의 여러 모듈에서 사용할 필요 유지하기위한 것입니다. 나는 실제로 그것을 사용하지 top않지만 필요한 경우 거기에서 사용할 수 있습니다.

나는이 점에 유의한다 beforeEach각과에 등록 된 모든 단일 테스트하기 전에 코드를 실행합니다 it그들은 내부에 표시할지 여부 describetop하거나에 표시 가져온 모듈의 . 를 사용 --recursive하면 beforeEach코드를 각 모듈에 복사해야하거나 beforeEach공통 모듈에서 가져온 함수를 호출하는 각 모듈에 후크 가있을 수 있습니다 .

또한 after후크는 제품군의 모든 테스트 후에 실행됩니다 . 로 복제 할 수 없습니다 --recursive. 각 모듈 --recursive에의 코드 를 사용 하여 추가 after하면 전체 테스트에 대해 한 번이 아닌 모듈 당 한 번 실행됩니다 .

모든 테스트가 단일 top제목 아래에 표시되도록하는 것은를 사용하여 복제 할 수 없습니다 --recursive. --recursive각 파일에있을 수 describe("top"있지만 이렇게 하면 각 파일에 대한 새 top제목 이 만들어 집니다.

common.js:

var chai = require("chai");

var options = {
    foo: "foo"
};

exports.options = options;
exports.chai = chai;
exports.assert = chai.assert;

이와 같은 이름 의 모듈을 사용하는 것은 여러 가지 작업을 반복 하지 않고 상태를 유지하지 않는 전역 읽기 전용 변수 또는 함수 를 보유 common하기 위해 일부 테스트 스위트에서 수행 한 작업입니다 . 나는 thgaskell의 대답과 같이 객체 를 오염시키지 않는 것을 선호합니다. 이 객체는 진정으로 전역 적이며 코드가로드 할 수있는 타사 라이브러리에서도 액세스 할 수 있기 때문입니다. 이것은 내 코드에서 허용되는 것이 아닙니다.requireglobal

a/a.js:

var common = require("../common");
var options = common.options;
var assert = common.assert;

it("blah a", function () {
    console.log(options.foo);
    assert.isTrue(false);
});

b/b.js:

it("blah b", function () {});

3
global범위를 오염해서는 안된다는 데 동의하지만 테스트 파일을 더 깨끗하게 유지하기 위해 어설 션 라이브러리에 사용합니다. 덮어 쓰는 것과는 다릅니다 global.process. global다른 라이브러리가 명시 적으로 호출하지 않는 한 지역 변수는 무시 됩니다 global.XYZ. 테스트 기간 동안 만 지속됩니다. 아직 날 다치게하지 않은,하지만 난 당신이 엉덩이 :) 나를 물린 순간 알려 드리겠습니다
thgaskell

예를 importTest들어과 부르기 의 차이점은 무엇입니까 require('path')()?
CherryNerd

@CreasolDev importTest함수는 단지 편의 함수입니다. 중요한 것은 require호출을 describe블록으로 래핑하는 것 입니다. require호출을 래핑 하는 것이 중요합니다. describe그렇지 않으면 모듈이 자체 블록에서 분리되지 않고 가져온 파일에 의해 설정된 후크가 잘못된 블록에 설정됩니다. 경우 importTest에 직접 호출로 대체 require랩핑없이 describe다음, 모듈을 a/a하고 b/b후크를 공유 할 것입니다. 예를 들어, beforeEach후크 세트 b/ba/a.
Louis

1
최상위 수준 설명에서 beforeEach와 같은 논리를 실행하지 않습니다. 각 파일이 beforeEach "stuff"를 수행하도록합니다. 이렇게하면 테스트를 서로 연결하고 관련없는 구현을 수행하게됩니다.
PositiveGuy

1
또한 importTest 함수가 아닌 해당 파일에서 설명을 래핑합니다. 최상위 어쨌든 자신의 테스트 스위트의 목적을 설명해야 각각의 파일에 대해 설명
PositiveGuy

35

이것이 질문과 직접적으로 연결되어 있지는 않지만 내가 찾고 있던 대답은 다음과 같습니다.

$ mocha --recursive

"test"폴더의 하위 디렉토리에있는 모든 테스트를 실행합니다. 산뜻한. 로드하려는 테스트 목록을 유지하고 실제로 항상 모든 것을 실행해야하는 시간을 절약합니다.


3
베스트 답변! 다른 제안 된 솔루션보다 훨씬 간단합니다.
caiosm1005

12
@ caiosm1005이 대답은 실제로 OP가 제시하는 문제를 해결 하는 것이 아닙니다 . 물론, OP가 원하는 것을 할 필요가 없다면 이것을 사용해야합니다. 여러 각 테스트 파일 포장하려는 경우, describe블록, describe블록 스팬 파일이 있음 --recursive을하지 않습니다. 그것이 OP의 문제를 해결하지 못하기 때문에 나는 그것을 "최고"라고 부르지 않을 것이다.
Louis

@louis - 당신이 각각 별도의 파일 포장 수 있다고 생각 describe블록
이안 제이미 슨

4
@IanJamieson OP는 단일 블록으로 여러 파일을 처리 하려고합니다 . 질문을보세요. "Controllers" 블록은 및 의 테스트를 포함해야합니다 . Mocha 호출에 두드리는 것은 마술처럼 블록을 생성하지 않습니다 . describedescribe./controllertests/messages.js./controllertests/users.js--recursivedescribe("Controllers"
Louis

3
@Louis 그냥 도와 주려고합니다. 마법처럼 describe블록을 만들려고해서 기분을 상하게했다면 미안합니다. 실제로 덤블도어에게서 배운 것입니다.
Ian Jamieson 2016

16

여러 테스트 파일을 실행하는 것을 방해하는 것은 없습니다. 일반적으로 각 테스트는 다른 테스트의 결과에 종속되어서는 안되므로 변수 공유는 원하는 작업이 아닙니다.

다음은 테스트 파일을 구성하는 방법의 예입니다.

.
├── app.js
└── test
    ├── common.js
    ├── mocha.opts
    │
    ├── controllers
    │   ├── messages-controller.js
    │   └── users-controller.js
    │
    └── models
        ├── messages-model.js
        └── users-model.js

그런 다음 mocha.opts파일 내부 에서 --recursive옵션 을 설정해야합니다 .

mocha.opts

--ui bdd
--recursive

모든 파일에 포함하려는 공통 모듈 이 있는 경우이를 파일에 추가 할 수 있습니다 common.js. test디렉토리 의 루트에있는 파일은 중첩 된 디렉토리의 파일보다 먼저 실행됩니다.

common.js

global.chai = require('chai');
global.assert = chai.assert;
global.expect = chai.expect;
chai.should();
chai.config.includeStack = true;

process.env.NODE_ENV = 'test';

// Include common modules from your application that will be used among multiple test suites.
global.myModule = require('../app/myModule');

3
누구든지 컨트롤러 및 모델 디렉토리의 파일에 대한 코드를 추가해도 될까요? 완전한 예가 있으면 좋을 것입니다.
Gavin

@Gavin-이것들은 단지 테스트 슈트 일 것이므로 그들은 포함 할 것입니다describe('mytest', function() { /* ..... etc */ });
Ian Jamieson

8

나는 이것이 오래된 게시물이라는 것을 알고 있지만 OP가 제안한 방법과 매우 유사한 나에게 좋은 해결책이었던 것을 차임하고 싶었습니다.

내가 작업중인 프로젝트는 잘 테스트되었으며 테스트는 계속 성장하고 있습니다. 내가 사용하는 결국 require은 동기 때문에 그것을 건축에 너무 많은 변화없이 테스트를 작성하는 데 쉽게 비트 수 있기 때문에 :

// inside test/index.js

describe('V1 ROUTES', () => {
  require('./controllers/claims.test');
  require('./controllers/claimDocuments.test');
  require('./controllers/claimPhotos.test');
  require('./controllers/inspections.test');
  require('./controllers/inspectionPhotos.test');
  require('./controllers/versions.test');
  require('./services/login.v1.test');
});

describe('V2 ROUTES', () => {
  require('./services/login.v2.test');
  require('./services/dec-image.v2.test');
});

describe('V3 ROUTES', () => {
  require('./services/login.v3.test');
  require('./services/getInspectionPhotosv3.test');
  require('./services/getPolicyInfo.v3.test');
});

describe('ACTIONS', () => {
  require('./actions/notifications.test');
});

2

같은 범주의 클래스에 대한 여러 테스트가있는 비슷한 문제가 있었고 IDE에서 쉽게 볼 수 있도록 그룹화하고 싶었습니다. 내 모든 테스트와 코드는 이미 ES6 모듈을 사용하고있었습니다 require. 다른 예제에서 본 것처럼 모두 사용하도록 다시 작성하고 싶지 않았습니다 .

내 "그룹화"를 describe내 보낸 다음 테스트 파일로 가져 와서 가져온 .NET Framework에 프로그래밍 방식으로 추가하여 문제를 해결했습니다 describe. 결국 모든 배관을 추상화하는 도우미 메서드를 만들었습니다.

someCategory.spec.js에서

const someCategory= describe("someCategory", () => {});


// Use this just like a regular `describe` to create a child of this scope in another file
export default function describeMember(skillName, testFn) {
  return describe(skillName, function configureContext() {
    // Make context a child of `someCategory` context
    function Context() {}
    Context.prototype = someCategory.ctx;
    this.ctx = new Context();
    // Re-parent the suite created by `describe` above (defaults to root scope of file it was created in)
    this.parent.suites.pop();
    someCategory.addSuite(this);
    // Invoke the fn now that we've properly set up the parent/context
    testFn.call(this);
  });
}

개별 테스트에서 :

import { default as describeCategoryMember } from './someCategory.spec';

describeCategoryMember('something', () => {
    describe('somethingElse', () => {
        ...
    });

    it('a test', () => {
        ...
    });
})

-11
describe( 'Running automation test, Please wait for all test to complete!'.red, function () {


    var run = require( './Test.js' );

    for ( var i = 0; i < 2; i++ ) {
        run.badLogin();
        run.loginLimited();
        run.acceptJob();
        run.drivingToJob();
        run.arrivedAtJob();
        run.towingJob();
        run.arrivedDestination();
        run.jobComplete();
        run.restrictionLicensePlate();
        run.newNodeMainMenu();
        run.newNodeMainMenuToDrafts();
        run.draftDelete();
        run.resetAllData();
        run.companyVehicle();
        run.actionsScreenClockInOut();
        run.mainMenuLogout();
        run.loginAdmin();
        run.actionsScreenLogout();
    }
} );

3
다른 사람들이 이것이 허용 가능한 대답인지 결정할 수 있도록 코드와 함께 설명을 추가하는 것이 가장 좋습니다.
Suever

2
왜 루프인가? 무엇입니까 ./Test.js? 누가 알아? 기록을 위해 나는 현재 모카 태그 에서 최고의 답변자입니다 . 나는 모카의 안팎을 알고 있지만이 대답을 이해할 수 없습니다.
Louis

@Louis 는 루프를 사용하여 테스트를 n 번 실행하고 싶었던 것 같습니다 .
Akash Agarwal 2018
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.