কোনও ES6 মডিউলটির আমদানিগুলিকে কীভাবে উপহাস করবেন?


141

আমার নিম্নলিখিত ES6 মডিউল রয়েছে:

network.js

export function getDataFromServer() {
  return ...
}

widget.js

import { getDataFromServer } from 'network.js';

export class Widget() {
  constructor() {
    getDataFromServer("dataForWidget")
    .then(data => this.render(data));
  }

  render() {
    ...
  }
}

আমি একটি মক উদাহরণ সহ উইজেট পরীক্ষা করার জন্য একটি উপায় খুঁজছি getDataFromServer। আমি যদি <script>কর্মের মতো ES6 মডিউলগুলির পরিবর্তে পৃথক গুলি ব্যবহার করি, তবে আমি আমার পরীক্ষার মতো লিখতে পারতাম:

describe("widget", function() {
  it("should do stuff", function() {
    let getDataFromServer = spyOn(window, "getDataFromServer").andReturn("mockData")
    let widget = new Widget();
    expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
    expect(otherStuff).toHaveHappened();
  });
});

তবে, যদি আমি ব্রাউজারের বাইরে পৃথকভাবে ES6 মডিউলগুলি পরীক্ষা করে নিই (যেমন মোচা + বাবেলের মতো) তবে আমি এই জাতীয় কিছু লিখব:

import { Widget } from 'widget.js';

describe("widget", function() {
  it("should do stuff", function() {
    let getDataFromServer = spyOn(?????) // How to mock?
    .andReturn("mockData")
    let widget = new Widget();
    expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
    expect(otherStuff).toHaveHappened();
  });
});

ঠিক আছে, তবে এখন getDataFromServerএটি উপলভ্য নয় window(ভাল, কিছু নেই window), এবং আমি সরাসরি widget.jsনিজের ক্ষেত্রের মধ্যে স্টাফ ইনজেক্ট করার কোনও উপায় জানি না ।

তাহলে আমি এখান থেকে কোথায় যাব?

  1. স্কোপ অ্যাক্সেস করার কোনও উপায় আছে widget.js, বা কমপক্ষে আমার নিজস্ব কোড দিয়ে এর আমদানিগুলি প্রতিস্থাপন করুন?
  2. যদি তা না হয় তবে আমি কীভাবে Widgetপরীক্ষামূলক করতে পারি ?

আমি বিবেচিত স্টাফ:

ক। ম্যানুয়াল নির্ভরতা ইনজেকশন।

সমস্ত আমদানি সরিয়ে ফেলুন widget.jsএবং কলার ডিপগুলি সরবরাহ করবেন বলে আশা করুন।

export class Widget() {
  constructor(deps) {
    deps.getDataFromServer("dataForWidget")
    .then(data => this.render(data));
  }
}

আমি উইজেটের এই জাতীয় পাবলিক ইন্টারফেসের সাথে জগাখিচু করা এবং প্রয়োগের বিশদটি প্রকাশ করে খুব অস্বস্তি বোধ করি। যাও না।


খ। আমদানিগুলি তাদের উপহাস করার অনুমতি দেওয়ার জন্য উন্মুক্ত করুন।

কিছুটা এইরকম:

import { getDataFromServer } from 'network.js';

export let deps = {
  getDataFromServer
};

export class Widget() {
  constructor() {
    deps.getDataFromServer("dataForWidget")
    .then(data => this.render(data));
  }
}

তারপর:

import { Widget, deps } from 'widget.js';

describe("widget", function() {
  it("should do stuff", function() {
    let getDataFromServer = spyOn(deps.getDataFromServer)  // !
      .andReturn("mockData");
    let widget = new Widget();
    expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
    expect(otherStuff).toHaveHappened();
  });
});

এটি কম আক্রমণাত্মক তবে প্রতিটি মডিউলের জন্য আমাকে প্রচুর বয়লারপ্লেট লেখার প্রয়োজন আছে এবং এখনও সমস্ত সময়ের getDataFromServerপরিবর্তে আমার ব্যবহারের ঝুঁকি রয়েছে deps.getDataFromServer। আমি এটি সম্পর্কে অস্বস্তি, তবে এটি এখন পর্যন্ত আমার সেরা ধারণা।


এই ধরণের আমদানির জন্য যদি কোনও নেটিভ মক সমর্থন না থাকে তবে আমি সম্ভবত আপনার ইএস 6 স্টাইল আমদানিকে কাস্টম মক্যাবল আমদানি সিস্টেমে রূপান্তর করতে বাবেলের জন্য একটি নিজস্ব ট্রান্সফর্মার লেখার বিষয়ে ভাবতে চাই। এটি নিশ্চিতভাবে সম্ভাব্য ব্যর্থতার আরেকটি স্তর যুক্ত করবে এবং কোডটি যা আপনি পরীক্ষা করতে চান তা পরিবর্তন করে, ...।
t.niese

আমি এখনই কোনও পরীক্ষার স্যুট সেট করতে পারছি না, তবে আমি 'नेटवर्क.js' মডিউল থেকে ডেটাফ্র্যাম সার্ভারের জন্য আমদানি করা রেফারেন্স সহ জেসমিনেরcreateSpy ( github.com/jasmine/jasmine/blob/… ) ফাংশনটি ব্যবহার করার চেষ্টা করব । যাতে, উইজেটের পরীক্ষার ফাইলগুলিতে আপনি getDataFromServer আমদানি করতে চান, এবং তারপরেlet spy = createSpy('getDataFromServer', getDataFromServer)
মাইক্রোফিড

দ্বিতীয় অনুমানটি কোনও ফাংশন নয়, 'নেটওয়ার্ক.js' মডিউল থেকে কোনও জিনিস ফেরত দেওয়া। এইভাবে, আপনি spyOnসেই বস্তুটিতে network.jsমডিউল থেকে আমদানি করতে পারেন । এটি সর্বদা একই বস্তুর একটি রেফারেন্স।
মাইক্রোফিড

প্রকৃতপক্ষে, এটি ইতিমধ্যে একটি অবজেক্ট, আমি যা দেখতে পাচ্ছি তা থেকে: babeljs.io/repl/…
মাইক্রোফিড

2
আমি সত্যিই বুঝতে পারি না কীভাবে নির্ভরতা ইঞ্জেকশনটি Widgetজনসাধারণের ইন্টারফেসে গণ্ডগোল করে ? Widgetবিশৃঙ্খলার সৃষ্টি হয় ছাড়া deps । নির্ভরতা সুস্পষ্ট করে তোলেন না কেন?
thebearingedge

উত্তর:


129

আমি import * as objআমার পরীক্ষাগুলির মধ্যে শৈলীটি নিয়োগ করতে শুরু করেছি , যা মডিউল থেকে সমস্ত রফতানি কোনও বস্তুর বৈশিষ্ট্য হিসাবে আমদানি করে যা পরে উপহাস করা যায়। রিওয়ায়ার বা প্রক্সিয়ার বা অন্য কোনও অনুরূপ কৌশল ব্যবহার করার চেয়ে এটি অনেক বেশি পরিচ্ছন্ন বলে আমি মনে করি। উদাহরণস্বরূপ, Redux ক্রিয়াকলাপকে যখন উপহাস করার দরকার হয় তখন আমি এটি প্রায়শই করেছি। আমি এখানে আপনার উদাহরণের জন্য যা ব্যবহার করতে পারি তা এখানে:

import * as network from 'network.js';

describe("widget", function() {
  it("should do stuff", function() {
    let getDataFromServer = spyOn(network, "getDataFromServer").andReturn("mockData")
    let widget = new Widget();
    expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
    expect(otherStuff).toHaveHappened();
  });
});

যদি আপনার ফাংশনটি কোনও ডিফল্ট রফতানি হয়ে থাকে, তবে import * as network from './network'উত্পাদন করবে {default: getDataFromServer}এবং আপনি নেটওয়ার্ক.ডেফল্টকে উপহাস করতে পারেন।


3
আপনি কি import * as objকেবল পরীক্ষায় বা আপনার নিয়মিত কোডেই ব্যবহার করেন ?
চাউ থাই

36
@ কারপেলিয়াম এই ইএস 6 মডিউল বিশ্লেষণের সাথে কাজ করবে না যেখানে আমদানি কেবল পঠনযোগ্য।
অ্যাশিশ

7
জেসমিন অভিযোগ করছে [method_name] is not declared writable or has no setterযা এস imp টি আমদানি স্থির থাকার কারণে এটি বোঝা যায়। কাজের উপায় আছে?
lpan

2
@ ফ্রানসিস্ক import(এর বিপরীতে require, যে কোনও জায়গায় যেতে পারে) উত্তোলন হয়ে যায়, যাতে আপনি প্রযুক্তিগতভাবে একাধিকবার আমদানি করতে পারবেন না। আপনার গুপ্তচর মত শব্দ অন্য কোথাও বলা হচ্ছে? পরীক্ষাগুলি বিশৃঙ্খলা থেকে দূরে রাখা (টেস্ট দূষণ হিসাবে পরিচিত) থেকে চালিয়ে যাওয়ার জন্য, আপনি নিজের গুপ্তচরগুলি আফটার আইচ (যেমন sinon.sandbox) এ রিসেট করতে পারেন। আমি বিশ্বাস করি জেসমিন স্বয়ংক্রিয়ভাবে এটি করে।
carpeliam

10
@ এজেন্ট 47 সমস্যাটি হ'ল যখন ES6 টি নির্দিষ্টভাবে এই উত্তরটিকে কাজ করা থেকে বিরত রেখেছে ঠিক ঠিক সেইভাবে আপনি যেভাবে উল্লেখ করেছেন, বেশিরভাগ লোকেরা importতাদের জেএস-এ লেখেন তারা সত্যিই ES6 মডিউল ব্যবহার করছেন না। ওয়েবপ্যাক বা ব্যাবেলের মতো কিছু বিল্ড-টাইম এ পদক্ষেপ নেবে এবং কোডের দূরবর্তী অংশগুলিকে কল করার জন্য এটিকে তাদের নিজস্ব অভ্যন্তরীণ ব্যবস্থায় রূপান্তরিত করবে (উদাহরণস্বরূপ __webpack_require__) অথবা প্রাক-ইএস 6 ডি ফ্যাক্টো স্ট্যান্ডার্ডগুলির মধ্যে একটি, কমনজেএস, এএমডি বা ইউএমডি রূপান্তর করবে । এবং এই রূপান্তর প্রায়শই অনুমানের সাথে কঠোরভাবে মেনে চলে না। এখন অনেকের জন্য, এখন অনেক দেব, এই উত্তরটি ঠিক কাজ করে। আপাতত
ডেমোনেক্সমাচিনা

31

@ কারপেলিয়াম সঠিক তবে নোট করুন যে আপনি যদি কোনও মডিউলে কোনও ফাংশন গুপ্তচর করতে চান এবং সেই ফাংশনটি কল করে সেই মডিউলটিতে অন্য কোনও ফাংশন ব্যবহার করতে চান তবে আপনাকে সেই ফাংশনটি রফতানির নেমস্পেসের অংশ হিসাবে কল করতে হবে অন্যথায় গুপ্তচর ব্যবহার করা হবে না।

ভুল উদাহরণ:

// mymodule.js

export function myfunc2() {return 2;}
export function myfunc1() {return myfunc2();}

// tests.js
import * as mymodule

describe('tests', () => {
    beforeEach(() => {
        spyOn(mymodule, 'myfunc2').and.returnValue = 3;
    });

    it('calls myfunc2', () => {
        let out = mymodule.myfunc1();
        // out will still be 2
    });
});

সঠিক উদাহরণ:

export function myfunc2() {return 2;}
export function myfunc1() {return exports.myfunc2();}

// tests.js
import * as mymodule

describe('tests', () => {
    beforeEach(() => {
        spyOn(mymodule, 'myfunc2').and.returnValue = 3;
    });

    it('calls myfunc2', () => {
        let out = mymodule.myfunc1();
        // out will be 3 which is what you expect
    });
});

4
আমি আশা করি আমি আরও 20 বার এই উত্তরটি দিতে পারতাম! ধন্যবাদ!
sfletche

এই ঘটনাটি কেন কেউ ব্যাখ্যা করতে পারেন? রফতানি.মিফুঙ্ক 2 () সরাসরি রেফারেন্স না হয়ে মাইফুঙ্ক 2 () এর একটি অনুলিপি?
কলিন হুইটমার্শ

2
@ কলিনউইটমার্শ একটি স্পাই ফাংশনের রেফারেন্সের সাথে এটি প্রতিস্থাপন না exports.myfunc2করা myfunc2পর্যন্ত এর প্রত্যক্ষ রেফারেন্স spyOn। একটি স্পাই অবজেক্টের spyOnমান পরিবর্তন করে exports.myfunc2এটি প্রতিস্থাপন করবে, যেখানে myfunc2মডিউলটির spyOn
স্কোপটিতে অচ্ছুত

স্থিতিস্থানের সাথে আমদানি করা উচিত নয় *এবং অবজেক্টের বৈশিষ্ট্যগুলি পরিবর্তন করা যায় না?
এজেন্ট 47

1
কেবলমাত্র একটি নোট যে export functionসাথে ব্যবহারের এই প্রস্তাবটি exports.myfunc2প্রযুক্তিগতভাবে কমনজ এবং ইএস 6 মডিউল সিনট্যাক্স মিশ্রণ করছে এবং ওয়েবপ্যাক (2+) এর নতুন সংস্করণগুলিতে এটি অনুমোদিত নয় যা সমস্ত বা অ-কিছুই ইএস 6 মডিউল সিনট্যাক্স ব্যবহারের প্রয়োজন নেই। আমি নীচে একটি উত্তর যুক্ত করেছি এটির ভিত্তিতে যা ES6 কঠোর পরিবেশে কাজ করবে।
কোয়ার্কলমোশন

6

আমি এমন একটি লাইব্রেরি কার্যকর করেছি যা টাইপস্ক্রিপ্ট শ্রেণীর আমদানির রান-টাইম বিদ্রূপের সমস্যাটি সমাধান করার চেষ্টা করে মূল ক্লাসের কোনও স্পষ্ট নির্ভরতা ইনজেকশন সম্পর্কে জানতে না।

লাইব্রেরিটি import * asসিনট্যাক্স ব্যবহার করে এবং তারপরে মূল রপ্তানি করা অবজেক্টটিকে স্টাব ক্লাসের সাথে প্রতিস্থাপন করে। এটি প্রকারের সুরক্ষা বজায় রাখে যাতে পরীক্ষার সাথে সম্পর্কিত পরীক্ষাটি আপডেট না করে কোনও পদ্ধতির নাম আপডেট করা হলে সংকলনের সময় আপনার পরীক্ষাগুলি ভেঙে যায়।

এই পাঠাগারটি এখানে পাওয়া যাবে: ts-mock- আমদানি


1
এই মডিউলটির আরও গিথুব তারক প্রয়োজন
এসডি

6

@ vdloo এর উত্তর আমাকে সঠিক দিকে নিয়ে গেছে, তবে একই ফাইলটিতে "এক্সপোর্ট" এবং ইএস 6 মডিউল "রফতানি" কীওয়ার্ড উভয়টিই আমার পক্ষে কার্যকর হয়নি (ওয়েবপ্যাক ভি 2 বা পরবর্তী অভিযোগ)। পরিবর্তে, আমি স্বতন্ত্র নামযুক্ত সমস্ত মডিউল রফতানি মোড়ানো এবং তারপরে আমার পরীক্ষার ফাইলে ডিফল্ট রফতানি আমদানি করে একটি ডিফল্ট (নামযুক্ত ভেরিয়েবল) রফতানি ব্যবহার করছি। আমি মোচা / সিনন সহ নিম্ন রফতানি সেটআপ ব্যবহার করছি এবং স্ট্রবিং রিওয়াইয়ার ইত্যাদি প্রয়োজন ছাড়াই সূক্ষ্ম কাজ করে .:

// MyModule.js
let MyModule;

export function myfunc2() { return 2; }
export function myfunc1() { return MyModule.myfunc2(); }

export default MyModule = {
  myfunc1,
  myfunc2
}

// tests.js
import MyModule from './MyModule'

describe('MyModule', () => {
  const sandbox = sinon.sandbox.create();
  beforeEach(() => {
    sandbox.stub(MyModule, 'myfunc2').returns(4);
  });
  afterEach(() => {
    sandbox.restore();
  });
  it('myfunc1 is a proxy for myfunc2', () => {
    expect(MyModule.myfunc1()).to.eql(4);
  });
});

সহায়ক উত্তর, ধন্যবাদ। কেবল উল্লেখ করতে চেয়েছিলাম যে let MyModuleডিফল্ট রফতানি (এটি কোনও কাঁচামাল জিনিস হতে পারে) ব্যবহার করার প্রয়োজন নেই। এছাড়াও, এই পদ্ধতিতে myfunc1()কল করার দরকার নেই myfunc2(), এটি সরাসরি এটি সরাসরি গুপ্তচর করার জন্য কাজ করে।
মার্ক এডিংটন

@ কির্ক্লমোশন: এটি প্রদর্শিত হয় যে আপনি দুর্ঘটনাক্রমে আপনার মূল অ্যাকাউন্টের চেয়ে আলাদা অ্যাকাউন্ট দিয়ে এটি সম্পাদনা করেছেন। এটা কেন আপনার সম্পাদনার একটি ম্যানুয়াল অনুমোদন মধ্য দিয়ে যেতে হয় - এটি মত থেকে ছিল করলেন না আপনি আমি অনুমান এই মাত্র একটি দুর্ঘটনা ছিল, কিন্তু, যদি ইচ্ছাকৃত ছিল, আপনি উচিত পুতুল যাতে আপনি অ্যাকাউন্ট সক অফিসিয়াল নীতি পড়ুন দুর্ঘটনাক্রমে নিয়ম লঙ্ঘন করবেন না
সুস্পষ্ট সংকলক

1
@ কনস্পিকিউসকম্পিলার মাথা আপ করার জন্য ধন্যবাদ - এটি একটি ভুল ছিল, আমি আমার কাজের ইমেল-সংযুক্ত এসও অ্যাকাউন্টের সাথে এই উত্তরটি পরিবর্তন করার ইচ্ছা করি নি।
কোয়ার্কলমোশন

এটি অন্য একটি প্রশ্নের উত্তর বলে মনে হচ্ছে! উইজেট.জে এবং নেটওয়ার্ক.জেএস কোথায়? এই উত্তরের কোনও অস্থায়ী নির্ভরতা নেই বলে মনে হচ্ছে, যা মূল প্রশ্নটিকে শক্ত করে তুলেছিল।
বেনেট ম্যাকএলউই

3

আমি এই সিনট্যাক্সটি কাজ করে দেখতে পেয়েছি:

আমার মডিউল:

// mymod.js
import shortid from 'shortid';

const myfunc = () => shortid();
export default myfunc;

আমার মডিউলটির পরীক্ষার কোড:

// mymod.test.js
import myfunc from './mymod';
import shortid from 'shortid';

jest.mock('shortid');

describe('mocks shortid', () => {
  it('works', () => {
    shortid.mockImplementation(() => 1);
    expect(myfunc()).toEqual(1);
  });
});

ডকটি দেখুন ।


+1 এবং কিছু অতিরিক্ত নির্দেশাবলীর সাথে: কেবল নোড মডিউলগুলি যেমন আপনার প্যাকেজ.জসনে রয়েছে এমন স্টাফগুলির সাথে কাজ করে বলে মনে হচ্ছে। এবং আরও গুরুত্বপূর্ণটি হ'ল জেস্ট ডক্সে উল্লেখ করা হয়নি এমন স্ট্রিংটি jest.mock()ধ্রুবকের নামের পরিবর্তে আমদানি / প্যাকেজ.জসনে ব্যবহৃত নামের সাথে মেলে। দস্তাবেজে এগুলি উভয়ই সমান, তবে import jwt from 'jsonwebtoken'আপনার মত কোডের সাথে মক সেটআপ করা দরকারjest.mock('jsonwebtoken')
ক্যাসক্লোটি

0

আমি নিজে চেষ্টা করে দেখিনি, তবে আমার মনে হয় বিদ্রূপ কাজ করতে পারে। এটি আপনাকে সরবরাহ করে এমন একটি মক দিয়ে সত্যিকারের মডিউলটি প্রতিস্থাপন করতে দেয়। এটি কীভাবে কাজ করে তার একটি ধারণা দেওয়ার জন্য নীচে একটি উদাহরণ দেওয়া হল:

mockery.enable();
var networkMock = {
    getDataFromServer: function () { /* your mock code */ }
};
mockery.registerMock('network.js', networkMock);

import { Widget } from 'widget.js';
// This widget will have imported the `networkMock` instead of the real 'network.js'

mockery.deregisterMock('network.js');
mockery.disable();

দেখে মনে হচ্ছে mockeryএটি আর রক্ষণাবেক্ষণ করা হয়নি এবং আমি মনে করি এটি কেবল নোড.জেএস এর সাথেই কাজ করে তবে এর চেয়ে কম কিছুই নয়, এটি বিদ্রূপ করা মডিউলগুলির জন্য একটি ঝরঝরে সমাধান that

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.