Mocha: يتم تشغيل "beforeEach" و "afterEach" في مجموعات / سياقات متداخلة

تم إنشاؤها على ٢٨ يونيو ٢٠١٣  ·  17تعليقات  ·  مصدر: mochajs/mocha

لا توجد وثائق في _when_ سيتم تشغيل beforeEach أو afterEach . ينص حدسي على أنه يجب تشغيله before / after كل كتلة describe / it في السياق الحالي.

ومع ذلك ، فإن السلوك الذي ألاحظه هو أن beforeEach و afterEach يتم تشغيلهما it before / after _ كل_ it كتلة في السياق الحالي وجميع السياقات المتداخلة.

لقد قمت بإنشاء دليل على المفهوم لإثبات حدوث السلوك الملحوظ: https://gist.github.com/twolfson/5883057#file -test-js

للراحة ، سأقوم بنسخ / لصق البرنامج النصي والإخراج هنا:

النصي

describe('An afterEach hook', function () {
  afterEach(function () {
    console.log('afterEach run!');
  });

  before(function () {
    console.log('before run!');
  });

  describe('in some nested contexts', function () {
    before(function () {
      console.log('nested before run!');
    });

    it('runs after this block', function () {
      console.log('nested it run!');

    });

    it('runs again after this block', function () {
      console.log('second nested it run!');
    });
  });
});

انتاج |

before run!
nested before run!
nested it run!
afterEach run!
second nested it run!
afterEach run!

السلوك الذي أتوقعه بشكل حدسي هو afterEach ليتم تشغيله مرة واحدة ، بعد second nested it .

before run!
nested before run!
nested it run!
second nested it run!
afterEach run!

حالة استخدامي للوظيفة البديهية هي تنظيف سياق this بعد اكتمال السياق. سيعمل التطبيق الحالي على تنظيف السياق بعد كل تأكيد.

afterEach(function () {
  var key;
  for (key in this) {
    delete this[key];
  }
});

describe('A banana', function () {
  before(function () {
    this.banana = new Banana();
  });

  describe('when peeled', function () {
    before(function () {
      this.peeledBanana = this.banana.peel();
    });

    it('is white', function () {
      assert.strictEqual(this.peeledBanana.color, 'white');
      // `afterEach` is invoked here, cleaning out `this`
    });

    it('is soft', function () {
      // `this.peeledBanana` is no longer defined since `afterEach` cleaned it out
      assert.strictEqual(this.peeledBanana.hardness, 'soft');
    });
  });
});

ومن الأمثلة المشابهة لذلك فتح معاملة قاعدة بيانات في كل سياق جديد لمجموعة اختبار.

يمكنني حلها عن طريق استدعاء after في كل سياق متداخل ولكني أشعر أنه قد يكون هناك رابط في إطار العمل.

التعليق الأكثر فائدة

لكل شخص لديه هذا السيناريو الشائع ، قمت بإنشاء هذه الوظيفة المساعدة التي تتكرر في جميع المجموعات في الكتلة الحالية وأضف خطافًا beforeAll لكل منها:

function beforeEachSuite (fn) {
  before(function () {
    let suites = this.test.parent.suites || []
    suites.forEach(s => {
      s.beforeAll(fn)
      let hook = s._beforeAll.pop()
      s._beforeAll.unshift(hook)
    })
  })
}

هذا يفتح حالة الاستخدام التي وصفتها منذ عام تقريبًا:

describe('Create Article', () => {
  beforeEachSuite(() => console.log('CLEAN DB'))

  context('When Article is valid', () => {
    before(() => console.log("INSERTING VALID ARTICLE"))

    it('should not fail')
    it('should have some properties')    
    it('should send an email')  
  })

  context('When Article is not valid', () => {
    before(() => console.log("INSERTING NOT VALID ARTICLE"))

    it('should fail')
    it('should not send an email')  
  })
})

ما زلت لا تفهم سبب عدم اعتبار حالة الاستخدام هذه مفيدة أو شرعية.
ربما يمكن تحويل هذا الحل إلى علاقات عامة مقابل beforeEachSuite و afterEachSuite

ال 17 كومينتر

بالنسبة لأولئك الفضوليين ، هذا هو الحل لحالة الاستخدام الخاصة بي:

// Before anything else is run
before(function () {
  // Iterate over all of the test suites/contexts
  this.test.parent.suites.forEach(function bindCleanup (suite) {
    // Attach an afterAll listener that performs the cleanup
    suite.afterAll(function cleanupContext () {
      var key;
      for (key in this) {
        delete this[key];
      }
    });
  });
});

+1

afterEach بعد كل مثيل Runnable ؛ في حالتك ، كتلة it() . إذا كنت لا تريد السلوك المتداخل ، فلا تداخل اختباراتك. تعديل هذا السلوك ليس مطروحا على الطاولة.

إذا كان اختبارك الثاني يعتمد على شيء محدد في اختبارك الأول ، فإن اختباراتك متسخة وأنت تفعل ذلك بشكل خاطئ. يجب ألا يكون الترتيب الذي يتم تنفيذ اختباراتك به مهمًا. اكتب اختباراتك وفقًا لذلك ، وستكون أكثر قيمة.

أيضًا ، ليس من الضروري وضع أي شيء على this 90٪ من الوقت.

describe('A banana', function () {
  var banana;

  before(function () {
    banana = new Banana();
  });

  describe('when peeled', function () {
    var peeledBanana;

    beforeEach(function () {
      // I'm assuming peel() has no side-effects since it returns a new object.
      peeledBanana = banana.peel();
    });

    it('is white', function () {
      assert.strictEqual(peeledBanana.color, 'white');
    });

    it('is soft', function () {
      assert.strictEqual(peeledBanana.hardness, 'soft');
    });
  });
});

هل هناك طريقة لتشغيل طرق الخطاف في مستوى الوصف () بدلاً من المستوى ()؟ قد يكون مفيدًا في بعض السيناريوهات.

RathaKM ما هي حالة الاستخدام؟

لست متأكدًا مما إذا كان هذا مثالًا جيدًا أم لا ، ولكن ، هل سيكون ما يلي حالة استخدام جيدة لهذا؟ RathaKM لا تتردد في

describe('A banana', function () {
  var banana;

  beforeEach(function () {
    banana = new Banana();
  });

  describe('when peeled', function () {
    var peeledBanana;

    before(function () {
      // Lets assume peel() HAS side-effects and doesn't return a new object.
      banana.peel();
      peeledBanana = banana;
    });

    it('is white', function () {
      assert.strictEqual(peeledBanana.color, 'white');
    });

    it('is soft', function () {
      assert.strictEqual(peeledBanana.hardness, 'soft');
    });
  });

  describe('when set on FIRE', function () {
    var flamingBanana;

    before(function () {
      // Same assumption as above
      banana.setOnFire();
      flamingBanana = banana
    });

    it('is hot', function () {
      assert.isAbove(flamingBanana.temperature, 9000);
    });
  });
});

cpoonolly : شكرًا على تعليقاتك

تم تقديم المشكلة التي كنت أواجهها في المثال أدناه.

var testData = [{country: 'NIL'}],
dataDriven = require('data-driven'),
assert = require('assert');

describe('@Testing_For_Describe_Level_Hook_Method_To_Update_TestData@', function () {

    describe('<strong i="8">@Updated</strong> testData for US@', function () {
        before(function (done) {
            testData = [{country: 'US'}];
            done();
        });
        dataDriven(testData, function () {
            it('expecting updated testData for US', function (ctx, done) {
                assert.equal(ctx.country, 'US');
                done();
            });
        });
    });

    describe('<strong i="9">@Updated</strong> testData for UK@', function () {
        before(function (done) {
            testData = [{country: 'UK'}];
            done();
        });
        dataDriven(testData, function () {
            it('expecting updated testData for UK', function (ctx, done) {
                assert.equal(ctx.country, 'UK');
                done();
            });
        });
    });
});

هنا ، ستفشل مجموعة الاختبار. نقوم بتحديث _testData_ داخل طريقة الخطاف "before ()" والتي سيتم استدعاؤها قبل كتلة "_it_". لكننا نستخدم المتغير _testData_ داخل _dataDriven () _ والذي سيتم تنفيذه قبل تنفيذ كتلة '_it_'.

لذا ، ما نحتاجه هنا هو مكان لتحديث المتغير قبل بدء تنفيذ كتلة _'it'_. قد نحتاج إلى تنفيذ طريقة الخطاف _before () _ قبل كتلة "الوصف" (وصف طريقة ربط المستوى).

امل الموضوع واضح الان

هل كان هناك أي نقاش إضافي حول هذا؟

لماذا لا يمكن الحصول على شيء مثل هذا؟

describe('Create Article', () => {
  beforeEach(() => console.log('CLEAN DB'))

  context('When Article is valid', () => {
    before(() => console.log("INSERTING VALID ARTICLE"))

    it('should not fail')
    it('should have some properties')    
    it('should send an email')  
  })

  context('When Article is not valid', () => {
    before(() => console.log("INSERTING NOT VALID ARTICLE"))

    it('should fail')
    it('should not send an email')  
  })
})
  • قم بتنظيف قاعدة البيانات قبل كل كتلة context .
  • قم بإعداد السيناريو قبل كل كتل it

أليست هذه حالة استخدام شرعية؟

@ marqu3z أحاول متابعة حالة الاستخدام الخاصة بك. إنه شرعي. يبدو أن المشكلة هي: قبل تشغيل الخطاف قبل كل خطاف؟ لكنك بحاجة إلى الخطاف السابق للتشغيل بعد الخطاف قبل كل خطاف؟

(هل تريد حقًا تنظيف قاعدة البيانات لكل حالة اختبار؟ يبدو أن حالة الاختبار الأولى فقط هي التي ستنجح ، ولن يكون لدى الآخرين أي بيانات. لكنني سأفترض أنك تريد تنظيف قاعدة البيانات لكل حالة اختبار).

فيما يلي محاولتي لحل حالة الاستخدام الخاصة بك بالنظر إلى Mocha كما هي:

(1) استخدم beforeEach ، لكن اقلب قيمة منطقية ، بحيث يتم تشغيل كل قبل مرة واحدة فقط (هذا سيء نوعًا ما)

describe('Create Article', () => {
  beforeEach(() => console.log('CLEAN DB'))

  context('When Article is valid', () => {
    let flip = true;
    beforeEach(() => flip && (flip = false; console.log('INSERTING VALID ARTICLE')))

    it('should not fail')
    it('should have some properties')    
    it('should send an email')  
  })

  context('When Article is not valid', () => {
   let flip = true;
    beforeEach(() => flip && (flip = false; console.log('INSERTING NOT VALID ARTICLE')))

    it('should fail')
    it('should not send an email')  
  })
})

(2) الطريقة الأخرى للقيام بذلك - هذا ليس أفضل بكثير!

describe('Create Article', () => {

  let cleanDB = function(fn){
    return function(done){
        actuallyCleanDB(function(err){
            if(err) return done(err);
            fn(done);
       });
    }
  };

  context('When Article is valid', () => {
    before(() => console.log('INSERTING VALID ARTICLE'))
    it('should not fail', cleanDB(function(done){})
    it('should have some properties', cleanDB(function(done){}))    
    it('should send an email', cleanDB(function(done){})) 
  })

  context('When Article is not valid', () => {
    before(() => console.log('INSERTING NOT VALID ARTICLE')))
    it('should fail', cleanDB(function(done){}))
    it('should not send an email',cleanDB(function(done){}))  
  })
})

يرجى إعلامي إذا فهمت مشكلتك ، وسأقضي المزيد من الدورات في التفكير في حل. لا يعتبر أي من حلي جيدًا جدًا ، لكني أريد فقط التأكد من فهمي للمشكلة التي تواجهك.

تضمين التغريدة

هل تقوم بتسجيل حالات الاختبار الخاصة بك () بشكل غير متزامن؟ إذا كان الأمر كذلك ، فهذا غير مسموح به. يجب عليك تسجيل describe/after/afterEach/before/beforeEach جميعًا بشكل متزامن.

// event loop tick X
 dataDriven(testData, function () {
     // it() must be called in the same event loop tick as X above
        it('expecting updated testData for UK', function (ctx, done) {
            assert.equal(ctx.country, 'UK');
            done();
       });
  });

أيضا ، من أين يأتي ctx؟ ربما لست على اطلاع بأحدث ميزات Mocha ، لكنني لم أرها من قبل

it(foo, function(ctx, done){
   // where is ctx coming from?
});

أنا في نفس السيناريو بالضبط وصف beforeEach describe beforeEach

لكل شخص لديه هذا السيناريو الشائع ، قمت بإنشاء هذه الوظيفة المساعدة التي تتكرر في جميع المجموعات في الكتلة الحالية وأضف خطافًا beforeAll لكل منها:

function beforeEachSuite (fn) {
  before(function () {
    let suites = this.test.parent.suites || []
    suites.forEach(s => {
      s.beforeAll(fn)
      let hook = s._beforeAll.pop()
      s._beforeAll.unshift(hook)
    })
  })
}

هذا يفتح حالة الاستخدام التي وصفتها منذ عام تقريبًا:

describe('Create Article', () => {
  beforeEachSuite(() => console.log('CLEAN DB'))

  context('When Article is valid', () => {
    before(() => console.log("INSERTING VALID ARTICLE"))

    it('should not fail')
    it('should have some properties')    
    it('should send an email')  
  })

  context('When Article is not valid', () => {
    before(() => console.log("INSERTING NOT VALID ARTICLE"))

    it('should fail')
    it('should not send an email')  
  })
})

ما زلت لا تفهم سبب عدم اعتبار حالة الاستخدام هذه مفيدة أو شرعية.
ربما يمكن تحويل هذا الحل إلى علاقات عامة مقابل beforeEachSuite و afterEachSuite

نعم من فضلك نحن بحاجة هذا.

هناك العديد من حالات الاستخدام مثل https://github.com/mochajs/mocha/issues/911#issuecomment -316736991

+1

+1

لقد تعثرت للتو في هذا الموضوع أبحث عن شيء مشابه. لذلك لأي شخص آخر يتعثر في هذا المنشور ...

لقد قمت بتكييف النهج الذي حددته @ marqu3z مع حزمة NPM الخاصة به: mocha-suite-hooks .

لذا ، إذا وجدت نفسك في موقف لا يكفي فيه before ، و beforeEach أكثر من اللازم ، جرّب beforeSuite .

لا تزال العبوة خامًا جدًا ، لذا فإن أي تعليقات ستكون محل تقدير كبير!

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات