<p>مصنع jest.mock لا يعمل داخل الاختبار</p>

تم إنشاؤها على ١٢ يناير ٢٠١٧  ·  38تعليقات  ·  مصدر: facebook/jest

هل تريد طلب ميزة أو الإبلاغ عن خطأ ؟
حشرة

ما هو السلوك الحالي؟

يبدو أن طريقة إنشاء نموذج مع مصنع لا تعمل داخل test أو it . إنه يعمل فقط عندما يتم تعريف النموذج على المستوى الجذر للملف.

هذا هو المثال الخاص بي على محاكاة:

jest.mock('services/feature', () => ({
    isEnabled: () => true
}));

ما هو السلوك المتوقع؟

يجب أن يعمل الاستهزاء بملف داخل الاختبار.

يرجى تقديم تكوين Jest الدقيق الخاص بك وذكر إصدار Jest والعقدة والغزل / npm ونظام التشغيل.

Jest 18.0.0 ، Node 7.4 ، macOS

Confirmed Discussion

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

لتغيير قيمة إرجاع نموذج ما بين الاختبارات ، يمكنك القيام بشيء مثل هذا:

jest.mock('whatever');

// Get the mock function
const whatever = require('whatever');

test('test 1', () => {
  whatever.mockImplementation(() => 'hello');
});

test('test 2', () => {
  whatever.mockImplementation(() => 'world');
});

ال 38 كومينتر

يتم رفع المكالمات jest.mock تلقائيًا إلى أعلى الملف باستخدام تحويل babel-jest. يمكنك حذف هذا السلوك مع jest.doMock . هل جربت ذلك؟

نفس الشيء مع doMock .

في المستندات ، يمكنني القراءة

ملاحظة: عند استخدام babel-jest ، سيتم رفع الدعوات المزيفة تلقائيًا إلى الجزء العلوي من كتلة التعليمات البرمجية. استخدم doMock إذا كنت تريد تجنب هذا السلوك صراحة.

لكن ... الاختبار عبارة عن كتلة رمز ، أليس كذلك؟ لذا في حالتي ، لا أتوقع أن أرى أي اختلافات.

إليك اختبار كامل

it('renders with the enabled feature', () => {
  jest.mock('services/feature', () => ({
      isEnabled: () => true
  }));

  const component = renderer.create(
      <MyComponent />
  );

  const tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});

هل يمكنك تقديم نسخة من هذا في مستودع GH؟

بالتأكيد. ها هو: https://github.com/tleunen/jest-issue-2582

يعرض كلا الاختبارين الحالة "Disabled" (معطل) على الرغم من أن أحدهما لديه محاكاة وهمية لعرض "Enabled" بدلاً من ذلك.
انظر هذه:
https://github.com/tleunen/jest-issue-2582/blob/master/src/MyComponent.js
https://github.com/tleunen/jest-issue-2582/blob/master/src/__tests__/MyComponent.spec.js

شكرا.

أي نصيحةcpojerthymikee لهذه المشكلة؟
لدي العديد من الاختبارات في نفس الملف وأود الحصول على ردود وهمية مختلفة لكل منهم.

يسعدني أني وجدت هذه المشكلة ، كنت أكسر رأسي بسبب عدم نجاح jest.mock() في نطاق describe . نقلته إلى الأعلى (أسفل وارداتي في ملف الاختبار) وهو يعمل.

بالنسبة لي ، ينطبق أيضًا على jest.mock() بدون مصنع ، باستخدام مجلد __mocks__ يحتوي على الملف الذي تم الاستهزاء به.

--تعديل

من الواضح أنه من الضروري رفع بيان jest.mock() إلى قبل بيانات الاستيراد. ومع ذلكtleunen، وهذا ربما يعني أنه من غير الممكن أن يسخر نفس الملف أكثر من مرة واحدة، مع استجابات مختلفة. ربما يتم خدمتك بشكل أفضل من خلال جعل وظيفة المصنع أكثر ديناميكية ، بحيث يمكن أن تقدم لك نتائج مختلفة في كل حالة اختبار.

في رأيي ، سيكون الأمر أكثر وضوحًا إذا تم وضع jest.mock() دائمًا خارج كتل describe و it . ولكن ينبغي بعد ذلك ذكر ذلك بوضوح في المستندات

لذلك يتم رفع jest.mock إلى نطاق الوظيفة ، ولهذا السبب لن يعمل مع require s (وبالتأكيد ليس import s التي يتم رفعها إلى نطاق الوحدة) إذا كنت نسميها داخل وظيفة أخرى غير describe (والتي يتم التعامل معها بشكل خاص من قبل Jasmine).
سيتم رفع مكالمتك jest.mock إلى أعلى هذه الوظيفة (وليس الوحدة) ، ولهذا السبب لن تعمل بالطريقة التي تتوقعها.

ننصح عمومًا بإعداد نماذج مختلفة في beforeEach و afterEach إذا كنت تريدهم مختلفين عبر حالات الاختبار.

يمكن لـ cpojer توضيح هذا بالتفصيل ، وإذا أردنا رفع المكالمات إلى النطاقات العليا.

هذا لأنك تطلب الوحدات النمطية الخاصة بك عند تهيئة الوحدة (باستخدام الاستيراد). يتم استدعاء jest.mock لاحقًا. طريقة حل هذا هي:

beforeEach(() => { // or the specific test
  jest.mock('MyModule', () => …);
  const MyModule = require('MyModule');
  …
});

إلخ.

إذا كان عليك القيام بذلك قبل كل اختبار ، فأنا غير واضح كيف ستفرق بين الاختبارات (فكيف ستقدم محاكاة مختلفة لكل اختبار؟)

إن وضعها داخل الاختبارات نفسها يعمل بالطبع.

هل يمكنك بعد ذلك تمرير الوحدة النمطية التي تم الاستهزاء بها داخل المكون الذي تم اختباره؟

ماذا لو لم أستورد / أطلب الملف الذي أرغب في محاكاة ساخرته (على سبيل المثال ، تبعية لملف آخر أقوم باستيراده) ولكني أريد أن يتم تحديده في نطاق وصف / كتلة؟ أو حتى إذا كنت أرغب في السخرية بشكل مختلف من اختبار beforeEach / beforeAll؟ هل هذه الحالات ممكنة؟

// A.js depends on B.js
import A from './A';

describe('myTest', () => {

    describe('myFirstScope', () => {
        beforeAll(() => {
            jest.mock('./B', () => ({
                myFirstMethod: jest.fn(),
            }));
        });

        // tests here
    });

    describe('mySecondScope', () => {
        beforeAll(() => {
            jest.mock('./B', () => ({
                mySecondMethod: jest.fn(),
            }));
        });

        // tests here
    });
});

في هذه الحالة ، تحتاج إلى طلب A بعد الاستهزاء بـ B. (لا تستخدم import ، ولكن require ).

تتطلب أ بعد الاستهزاء ب

لم ينجح معي ، ما زلت أرى النسخة الأصلية من B وهي تمر من خلال النتيجة

GoldAnna هل وجدت حلاً لهذه المشكلة؟

alayor لم أفعل

بقدر ما واجهت هذه المشكلة ، فأنا مقتنع الآن أنني إما لا أختبر بشكل صحيح ، أو لا أستخدم jest كما أراد المؤلفون ، أو مزيجًا من الاثنين معًا. دليل آخر هو أن أيا من الأمثلة ذات الصلة بالموضوع في وثائق jest تبدو وكأنها أمثلة من العالم الحقيقي بالنسبة لي ... ربما تكون كذلك ومن المحتمل أن أسلوبي غير صحيح.

ومع ذلك ، فإن ما يلي يناسبني ، وتنجح جميع الاختبارات التالية. لاحظ أنه للعودة إلى الإصدار الأصلي من ModuleB ، يجب أن أتصل بكل من jest.resetModules() و jest.unmock('./moduleB') ... لا يهم ترتيب هذين.

// Module A
const ModuleB = require('./moduleB');
const ModuleA = function() {
  this.title = new ModuleB().title;
  return this;
};
module.exports = ModuleA;

// Module B
const ModuleB = function() {
  this.title = 'Module B - Original'
  return this;
};
module.exports = ModuleB;

// Tests
describe('Jest a few tests', () => {
  it('should do something', () => {
    jest.resetModules();
    jest.mock('./moduleB', () => function() {
      this.title = 'Module B - Mock 1'
      return this;
    });
    const ModuleA = require('./moduleA');
    const moduleA = new ModuleA();
    expect(moduleA.title).toEqual('Module B - Mock 1');
  });

  it('should do something else', () => {
    jest.resetModules();
    jest.mock('./moduleB', () => function() {
      this.title = 'Module B - Mock 2'
      return this;
    });
    const ModuleA = require('./moduleA');
    const moduleA = new ModuleA();
    expect(moduleA.title).toEqual('Module B - Mock 2');
  });

  it('should do something original', () => {
    jest.resetModules();
    jest.unmock('./moduleB');
    const ModuleA = require('./moduleA');
    const moduleA = new ModuleA();
    expect(moduleA.title).toEqual('Module B - Original');
  });
});

مهلا،

لا شيء هنا يناسبني.
هل يمكن لأي شخص أن يشرح لماذا لا يمكن استخدام jest.mock بداخله؟

شكرا لك

أعتقد أن هذه لا تزال مشكلة ينبغي إعادة فتحها كطلب ميزة. أريد أن أكتب الاختبارات في عزلة. إلقاء الأشياء في مجلد mocks أو إعادة توصيل الأسلاك بـ before: ينتهي كل منها عادةً بدرج غير مرغوب فيه من نماذج mocks / الغريبة للبيانات التي يتم سحبها في كل اختبار. أريد أن أكتب نموذجًا وهميًا وأن أجري اختبارًا صغيرًا.

ليس لدينا طريقة حقيقية لعزل الاختبارات الفردية (مع الأخذ في الاعتبار test.concurrent ). إذا اعتمدنا واجهة برمجة تطبيقات مشابهة لـ tap أو ava ، فسيكون ذلك ممكنًا ، لكنني لا أعتقد أنه ممكن مع القيود التي تفرضها واجهة برمجة التطبيقات العالمية الحالية. سعيد للغاية أن تثبت خطأ!

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

gcox هل جربت الاستهزاء (وتطلب الوحدة النمطية A بعد ذلك) في المستوى الأعلى من الوحدة ثم تغيير تنفيذ النموذج لكل اختبار يحتاج إلى سلوك مختلف؟ يمكنك استخدام mockImplementation للقيام بذلك. هذه هي الطريقة التي حلنا بها هذا في مجموعات الاختبار الخاصة بنا.

antgonzales أعتقد أنه من الصعب القيام بذلك إذا تم رفع واردات الوحدة إلى أعلى الوحدة النمطية. يبدو تعديل مراجع الوحدة النمطية التي تم استيرادها مسبقًا غير تافه إلى مستحيل في العقدة.

تضمين التغريدة هذا ليس فقط ما كان يطلبه OP ، IMO. أعتقد أنهم كانوا يسألون ، على وجه التحديد ، "كيف أجبر require('whatever') على إرجاع محاكاة مختلفة عبر عدة اختبارات متجاورة بدلاً من نفس الكائن؟".

لتغيير قيمة إرجاع نموذج ما بين الاختبارات ، يمكنك القيام بشيء مثل هذا:

jest.mock('whatever');

// Get the mock function
const whatever = require('whatever');

test('test 1', () => {
  whatever.mockImplementation(() => 'hello');
});

test('test 2', () => {
  whatever.mockImplementation(() => 'world');
});

لقد نجحت إجابة SimenB نجحت أيضًا ، وهي أبسط من ذلك بكثير!

rafaeleyng لكن SimenB لا يعمل إذا كان ما تقوم بتصديره من الوحدة ليس وظيفة ...

يحتوي مثال gcox على معظم المعلومات التي كنت أبحث عنها في المستندات خلال الساعات القليلة الماضية. أقترح أن يتم تضمينه في الوثائق الرسمية التي هي نادرة للغاية في الوقت الحالي على أي حال.

schumannd صحيح. يرجى جعل الوثائق الرسمية أكثر وضوحًا ونقاءً.

يرحب PRs دائمًا بتحسين المستندات 🙂

نموذج الوحدة على أساس
https://github.com/facebook/jest/issues/2582#issuecomment -378677440 ❤️

Heya ، وجدت هذا عبر المشكلة المرتبطة واكتشفتها:

jest.mock('child_process')
const childProcess = require('child_process')

describe('foo', () => {
  test('bar', () => {
    childProcess.execSync.mockImplentation(jest.fn().mockReturnValueOnce('wibble'))
    // code that itself requires child_process
    expect(childProcess.execSync.mock.results[0]).toEqual('wibble')
  })

  test('baz', () => {
    childProcess.execSync.mockImplentation(jest.fn().mockReturnValueOnce('wobble'))
    // code that itself requires child_process
    expect(childProcess.execSync.mock.results[0]).toEqual('wobble')
  })
})

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

إذا كنت تحبني فقط تحتاج إلى وظيفة واحدة ، يمكنك تبسيط الأمر برمته:

jest.mock('child_process')
const { execSync } = require('child_process')

describe('foo', () => {
  test('bar', () => {
    execSync.mockImplentation(jest.fn().mockReturnValueOnce('wibble'))
    // code that itself requires child_process
    expect(execSync.mock.results[0]).toEqual('wibble')
  })

  test('baz', () => {
    execSync.mockImplentation(jest.fn().mockReturnValueOnce('wobble'))
    // code that itself requires child_process
    expect(execSync.mock.results[0]).toEqual('wobble')
  })
})

ماذا عن الاستهزاء بالتبعية غير الوظيفية مثل ملفات json أو الثوابت المعينة. يرجى توضيح الوثائق حول كيفية التعامل مع هذا ...

gcox الحل الخاص بك هو الحل الوحيد الذي وجدته عندما تقوم وحدة مستوردة قيد الاختبار باستيراد وحدة أخرى كان لدي نموذج يدوي لها في مجلد __mocks__ .

على سبيل المثال ، يستدعي ملف الاختبار jest.mock('./ModuleA') ، والذي يحتوي على نسخة وهمية في __mocks__/ModuleA.js . لكن ModuleA ليس قيد الاختبار ، ModuleB - الذي يتطلب ModuleA - هو ما يخضع للاختبار. بدون الحل الخاص بك ، سيحصل ModuleB على التنفيذ الفعلي لـ ModuleA ، وليس النموذج.

يبدو هذا سلوكًا غريبًا حقًا من المزاح. أتوقع أنه عند استدعاء jest.mock على وحدة نمطية ، فإن أي وحدة قيد الاختبار تعتمد على الوحدة النمطية التي تم الاستهزاء بها ستستخدم النموذج الوهمي. هل يبدو هذا غريباً لأنه لا يعمل بهذه الطريقة ، أم أنني أفعل ذلك بشكل غير صحيح تمامًا؟

SimenB في المثال الخاص بك ، أنت تطلب الوحدة النمطية التي تم

عملت SimenB الحل الأبسط بالنسبة لي. شكرا! تمكنت Wish من العثور عليها في وقت سابق قبل أن أمضي الوقت بعدة طرق مختلفة

في حالتي كنت أستهزئ وأستورد المسار الخاطئ للوحدة التي كنت أرغب في إيقافها. كان لدي غلاف مختلف في مسار الملف ، لذا اعتقد المحرر أنه بخير ولكنه فشل.

كنت

const { stubMethod } = require("./path/to/File");
jest.mock("./path/to/File");

تم التغيير إلى (تغيير الغلاف من File إلى file ):

const { stubMethod } = require("./path/to/file");
jest.mock("./path/to/file");

آمل أن يساعد هذا شخص آخر.

ياسمين spyOn() ليس لديه مثل هذه الإختبارات _داخل_الاختبارات. من المفترض أن تستخدم Jest الياسمين بشكل افتراضي؟ لماذا لا يعمل داخل الاختبار؟

مثال الياسمين:

spyOn(require('moduleB'), 'functionA').and.callFake(() => true);

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

test('moduleName 2', () => {
  jest.doMock('../moduleName', () => {
    return {
      __esModule: true,
      default: 'default2',
      foo: 'foo2',
    };
  });
  return import('../moduleName').then(moduleName => {
    expect(moduleName.default).toEqual('default2');
    expect(moduleName.foo).toEqual('foo2');
  });
});

في هذا المثال ، يمكنك الوصول إلى الإصدار الجديد من "moduleName" داخل وظيفة الاختبار فقط. بالنسبة لي ، من المهم جدًا أن يتمكن الرمز "غير التجريبي" الخاص بي من الوصول إلى النسخة التي تم الاستهزاء بها من الوحدة أيضًا. على سبيل المثال ، فإن الفصل الذي أستخدمه داخل الاختبار الخاص بي ، والذي قام باستيراد "moduleName" سيظل يستخدم الإصدار الأصلي ، وليس الإصدار المسخر منه.

يبدو أنه مرتبط: https://github.com/facebook/jest/issues/3236

نصيحة - إذا كانت لديك وحدة تقوم بتصدير قيمة أولية ، على سبيل المثال:

'' auth.js
تصدير const isUserAdmin = getSetting ('admin') ؛

And you want to use a mock value instead, in the test, then a simple require and assignment seems to do the trick:

```deleteUser.js
const auth = require('../auth');

describe('deleteUser', () => {
  it('can delete if admin', () => {
    auth.isUserAdmin = true;

    // call method that depends on isUserAdmin value
    // and assert on the result
  });
});

لذلك ، إذا كنت تريد السخرية من كائن يتم استخدامه بشكل غير مباشر بواسطة الكود ، فإنك تختبر وظيفة jest.doMock() لن تعمل:

import myModuleToTest from './myModuleTotest'

describe('Given my module', () => {
  it('property1 will work as expect', () => {
    // Testing parts of the module that don't need to be mocked
  })

  it('property2 will work as expected', () => {
    jest.doMock('./myOtherModule', () => {
      return {
        __esModule: true,
        default: 'default2',
        foo: 'foo2',
      };
    });

    import('./myOtherModule').then(myOtherModule => {
      // I'm not interested on the mocked module myOtherModule but on the module that makes use of it
      myModuleToTest.doSomethingToSomeProperty(); // At this point myOtherModule's original module and not its mocked version will be used by myModuleToTest
      expect(myModuleToTest.someProperty).toBe('thisWillFail'); // The test won't pass because the mocked version wasn't used
    });
  });
});

اعتبارًا من Jest 26 ، لا توجد طريقة للسخرية أكثر من مرة من وحدة تقوم بتصدير Object يتم استخدامه بشكل غير مباشر (أعني السخرية من شيء آخر غير Function حيث لا يوجد mockFn.mockImplementation(fn) للسخرية من Objects ). هل هذا صحيح أم أني أفتقد شيئًا؟ الحل الوحيد إذن هو وجود أكثر من ملف اختبار لاختبار نفس الوحدة.

يجب عليك استيراد myModuleToTest بعد النموذج الخاص بك لأنه إذا تم استيراده
قبل أن وهمية لا معنى لها. لذا ، لا تستخدم استيراد .... في الأعلى أو
داخل رد الاتصال لأنه تم رفعه على أي حال.

يوم الثلاثاء ، 7 يوليو ، 2020 ، 10:24 مساءً أنطونيو ريدوندو [email protected]
كتب:

لذلك ، في الأساس ، إذا كنت تريد السخرية من كائن يتم استخدامه بشكل غير مباشر بواسطة ملف
لن تعمل الكود الذي تختبر به وظيفة jest.doMock ():

استيراد myModuleToTest من "./myModuleTotest"
it ('will work'، () => {
jest.doMock ('./ myOtherModule'، () => {
إرجاع {
__esModule: صحيح ،
الافتراضي: "افتراضي 2"،
foo: "foo2" ،
} ؛
}) ؛

إرجاع الاستيراد ('../ myOtherModule'). ثم (myOtherModule => {
// لست مهتمًا بالوحدة النمطية myOtherModule التي تم الاستخفاف بها ولكنني مهتم بالوحدة التي تستفيد منها
myModuleToTest.doSomethingToSomeProperty () ، // في هذه المرحلة ، سيتم استخدام الوحدة النمطية الأصلية لـ myOtherModule وليس نسختها المزيفة بواسطة myModuleToTest
توقع (myModuleToTest.someProperty) .toBe ('thisWillFail') ؛ // لن يجتاز الاختبار لأنه لم يتم استخدام النسخة التي تم الاستهزاء بها
}) ؛}) ؛

اعتبارًا من Jest 26 ، لا توجد طريقة للسخرية من وحدة تقوم بتصدير كائن (I.
تعني شيئًا آخر غير الوظيفة) يتم استخدامه بشكل غير مباشر. هذا هو
صحيح أم أني أفتقد شيء؟ الحل الوحيد إذن هو الحصول على المزيد
من ملف اختبار واحد لاختبار نفس الوحدة.

-
أنت تتلقى هذا لأنك علقت.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/facebook/jest/issues/2582#issuecomment-655110424 ، أو
إلغاء الاشتراك
https://github.com/notifications/unsubscribe-auth/AAJR3UW6HARW44ZLKAUB7PLR2N77NANCNFSM4C4I7QSQ
.

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