এটি কি মকিতোর রিসেট পদ্ধতির উপযুক্ত ব্যবহার?


68

আমার টেস্ট ক্লাসে আমার একটি ব্যক্তিগত পদ্ধতি রয়েছে যা একটি ব্যবহৃত ব্যবহৃত Barঅবজেক্ট তৈরি করে। Barকন্সট্রাকটর আহ্বান someMethod()আমার ব্যঙ্গ বস্তু পদ্ধতি:

private @Mock Foo mockedObject; // My mocked object
...

private Bar getBar() {
  Bar result = new Bar(mockedObject); // this calls mockedObject.someMethod()
}

আমার পরীক্ষার কয়েকটি পদ্ধতিতে আমি যাচাই করতে চাই someMethodসেই নির্দিষ্ট পরীক্ষার দ্বারাও আমন্ত্রণ জানানো হয়েছিল। নিম্নলিখিত মত কিছু:

@Test
public void someTest() {
  Bar bar = getBar();

  // do some things

  verify(mockedObject).someMethod(); // <--- will fail
}

এটি ব্যর্থ হয়েছে, কারণ উপহাস করা বস্তুটি someMethodদু'বার ডেকেছিল। আমি চাই না যে আমার পরীক্ষার পদ্ধতিগুলি আমার পদ্ধতির পার্শ্ব প্রতিক্রিয়াগুলি সম্পর্কে যত্নশীল getBar(), সুতরাং আমার মক অবজেক্টটির শেষে পুনরায় সেট করা কি যুক্তিযুক্ত হবে getBar()?

private Bar getBar() {
  Bar result = new Bar(mockedObject); // this calls mockedObject.someMethod()
  reset(mockedObject); // <-- is this OK?
}

আমি জিজ্ঞাসা করি, কারণ ডকুমেন্টেশনটি মক অবজেক্টগুলি পুনরায় সেট করার পরামর্শ দেয় সাধারণত খারাপ পরীক্ষার সূচক। তবে এটি আমার কাছে ঠিক আছে।

বিকল্প

বিকল্প পছন্দটি কল করছে বলে মনে হচ্ছে:

verify(mockedObject, times(2)).someMethod();

যা আমার মতে প্রতিটি পরীক্ষা getBar()কোনও লাভের জন্যই তার প্রত্যাশা সম্পর্কে জানতে বাধ্য করে ।

উত্তর:


60

আমি বিশ্বাস করি যে এটি ব্যবহারের reset()ক্ষেত্রে ঠিক আছে of আপনি যে পরীক্ষাটি লিখছেন তা পরীক্ষা করছে যে "কিছু জিনিস" একক কলকে ট্রিগার করে someMethod()verify()বিভিন্ন সংখ্যার আহ্বান সহ বিবৃতিটি লেখার ফলে বিভ্রান্তির সৃষ্টি হতে পারে।

  • atLeastOnce() মিথ্যা পজিটিভের জন্য অনুমতি দেয়, যা আপনার পরীক্ষাগুলি সর্বদা সঠিক হওয়া চাই বলে একটি খারাপ জিনিস।
  • times(2)মিথ্যা ধনাত্মকটি প্রতিরোধ করে, তবে মনে হয় আপনি "আমি জানি কনস্ট্রাক্টর একটি যুক্ত করেছি" বলার চেয়ে আপনি দুটি আহ্বানের প্রত্যাশা করছেন। আরও আরও, কোনও অতিরিক্ত কল যুক্ত করার জন্য যদি কনস্ট্রাক্টরের কিছু পরিবর্তন হয়, পরীক্ষায় এখন একটি মিথ্যা পজিটিভ হওয়ার সুযোগ রয়েছে। এবং কলটি সরিয়ে দেওয়ার ফলে পরীক্ষাটি ব্যর্থ হতে পারে কারণ টেস্টটি যা পরীক্ষা করা হচ্ছে তার পরিবর্তে এখন ভুল।

reset()সহায়ক পদ্ধতিতে ব্যবহার করে , আপনি এই দুটি সমস্যা এড়াতে পারেন। তবে আপনার সতর্ক হওয়া দরকার যে এটি আপনার করা কোনও স্ট্যাবিও পুনরায় সেট করবে, তাই সতর্কতা অবলম্বন করুন। reset()নিরুৎসাহিত হওয়ার প্রধান কারণ হ'ল প্রতিরোধ করা

bar = mock(Bar.class);
//do stuff
verify(bar).someMethod();
reset(bar);
//do other stuff
verify(bar).someMethod2();

ওপি এটি করার চেষ্টা করছে না। ওপি, আমি ধরে নিচ্ছি, একটি পরীক্ষা আছে যা কনস্ট্রাক্টরের অনুরোধটি যাচাই করে। এই পরীক্ষার জন্য, রিসেটটি এই একক ক্রিয়াটি বিচ্ছিন্ন করার অনুমতি দেয় এবং এটি কার্যকর। এই কয়েকটি ক্ষেত্রে এর একটি reset()হিসাবে সহায়ক হতে পারে। অন্যান্য বিকল্পগুলি যা এটি ব্যবহার করে না সেগুলির সবগুলিতে বিপর্যয় রয়েছে। ওপি এই পোস্টটি করেছে তা প্রমাণ করে যে তিনি পরিস্থিতি সম্পর্কে চিন্তাভাবনা করছেন এবং অন্ধভাবে পুনরায় সেট করার পদ্ধতিটি ব্যবহার করছেন না।


17
আমি আশা করি মকিতো কেবল পুনরায় যাচাই করার উদ্দেশ্যে (..., বার (...)) অতীতের মিথস্ক্রিয়াগুলি ভুলে যাওয়ার জন্য এবং স্টাবিংটি চালিয়ে যাওয়ার জন্য পুনরায় সংস্থাগুলি () কল সরবরাহ করেছিল। এটি {সেটআপের পরীক্ষার পরিস্থিতি তৈরি করবে; আইন; যাচাই করুন; ডিল করা এত সহজ। এটি হবে {সেটআপ; resetInteractions; আইন; যাচাই করুন}
আরকাদি

2
প্রকৃতপক্ষে মকিতো ২.১ এটি স্টাবগুলি পুনরায় সেট না করেই অনুরোধগুলি সাফ করার একটি উপায় সরবরাহ করে:Mockito.clearInvocations(T... mocks)
কলিন ডি বেনেট

6

স্মার্ট মকিতো ব্যবহারকারীরা খুব কমই রিসেট বৈশিষ্ট্যটি ব্যবহার করেন কারণ তারা জানেন যে এটি দরিদ্র পরীক্ষার লক্ষণ হতে পারে। সাধারণত, আপনাকে আপনার উপহাসগুলি পুনরায় সেট করার দরকার নেই, প্রতিটি পরীক্ষার পদ্ধতির জন্য কেবল নতুন মক তৈরি করুন।

পরিবর্তে reset()দয়া করে দীর্ঘ, ওভার-সুনির্দিষ্ট পরীক্ষাগুলির চেয়ে সহজ, ছোট এবং দৃষ্টি নিবদ্ধ পরীক্ষার পদ্ধতিগুলি বিবেচনা করুন। প্রথম সম্ভাব্য কোড গন্ধ reset()পরীক্ষা পদ্ধতির মাঝখানে।

থেকে নিষ্কাশিত mockito ডক্স

আমার পরামর্শ হ'ল আপনি ব্যবহার এড়াতে চেষ্টা করুন reset()। আমার মতে, আপনি যদি কোনও ম্যাথোডে দু'বার কল করেন তবে এটি পরীক্ষা করা উচিত (সম্ভবত এটি কোনও ডাটাবেস অ্যাক্সেস বা অন্য দীর্ঘ প্রক্রিয়া যা আপনি যত্ন নিতে চান)।

আপনি যদি সত্যিই এটি সম্পর্কে চিন্তা না করেন তবে আপনি ব্যবহার করতে পারেন:

verify(mockedObject, atLeastOnce()).someMethod();

মনে রাখবেন যে এটি শেষেরটি একটি মিথ্যা ফলাফলের কারণ হতে পারে, যদি আপনি getBar থেকে কিছু মেঠোড কল করেন, এবং পরে না (এটি একটি ভুল আচরণ, তবে পরীক্ষা ব্যর্থ হবে না)।


2
হ্যাঁ, আমি সেই সঠিক উক্তিটি দেখেছি (আমি আমার প্রশ্ন থেকে এটি সংযুক্ত করেছি)। আমার উপরের উদাহরণটি "খারাপ" কেন তা নিয়ে আমি এখনও একটি শালীন যুক্তি দেখতে পাইনি। আপনি একটি সরবরাহ করতে পারেন?
ডানকান জোন্স

আপনার যদি আপনার উপহাসের বিষয়গুলি পুনরায় সেট করার দরকার হয় তবে মনে হয় আপনি নিজের পরীক্ষায় খুব বেশি স্টাফ পরীক্ষা করার চেষ্টা করছেন। আপনি এটিকে দুটি পরীক্ষায় ভাগ করতে পারেন, ছোট স্টাফের পরীক্ষা করে testing যাই হোক না কেন, কেন আপনি getBar পদ্ধতিতে যাচাই করছেন তা আমি জানি না, আপনি কী পরীক্ষা করছেন তা ট্র্যাক করা শক্ত। আমি আপনাকে পরামর্শ দিচ্ছি যে আপনার ক্লাসটি কী করা উচিত (আপনার যদি কিছু মেথডকে কমপক্ষে দু'বার কল করা উচিত তবে কমপক্ষে একবারে, কেবল একবারে, কখনই নয়) এবং প্রতিটি যাচাই একই জায়গায় করুন।
গ্রেজ

আমি আমার প্রশ্নটি সম্পাদিত করেছি যে হাইলাইট করার জন্য যে আমি verifyআমার ব্যক্তিগত পদ্ধতিতে কল না করলেও সমস্যাটি অব্যাহত থাকে (যা আমি সম্মত করি, সম্ভবত সেখানে নেই)। আপনার উত্তর পরিবর্তন হবে কিনা এ বিষয়ে আমি আপনার মন্তব্যে স্বাগত জানাই।
ডানকান জোন্স

রিসেটটি ব্যবহার করার অনেকগুলি ভাল কারণ রয়েছে, আমি সেই ক্ষেত্রে সেই মকিতো উদ্ধৃতিটিতে খুব বেশি মনোযোগ দেব না। টেস্ট স্যুটটি চালানো যখন অযাচিত ইন্টারঅ্যাকশনগুলির কারণ হয়ে থাকে আপনি স্প্রিংয়ের জুনিত ক্লাস রানার থাকতে পারেন, বিশেষত আপনি যদি এমন টেস্টিং করেন যা মক্কেল ডেটাবেস কল বা কলগুলিতে জড়িত যেগুলি ব্যক্তিগত পদ্ধতিগুলিতে জড়িত যাতে আপনি প্রতিফলন ব্যবহার করতে চান না।
স্যান্ডি সিমন্তন

যখন আমি একাধিক জিনিস পরীক্ষা করতে চাই তখন আমি সাধারণত এটি একটি কঠিন জিনিসটি পাই, তবে জুনিট পরীক্ষার প্যারামিটারাইজ করার কোনও সহজ (!) উপায় দেয় না। NUnit এর বিপরীতে টীকাগুলির সাহায্যে উদাহরণস্বরূপ।
স্টিফান হেন্ডরিক্স

3

একেবারে না. যেমনটি প্রায়শই ঘটে থাকে, পরিষ্কার পরীক্ষা লেখার ক্ষেত্রে আপনার যে অসুবিধা হচ্ছে তা হ'ল আপনার প্রোডাকশন কোডের নকশা সম্পর্কে একটি প্রধান লাল পতাকা। এই ক্ষেত্রে, সর্বোত্তম সমাধানটি হল আপনার কোডটি রিফ্যাক্টর করা যাতে বারের নির্মাণকারী কোনও পদ্ধতি কল না করে।

কনস্ট্রাক্টরদের লজিক চালানো উচিত নয়, নির্মাণ করা উচিত। পদ্ধতির রিটার্ন মান নিন এবং এটি কনস্ট্রাক্টর প্যারামিটার হিসাবে পাস করুন।

new Bar(mockedObject);

হয়ে:

new Bar(mockedObject.someMethod());

যদি এর ফলে অনেক জায়গায় এই যুক্তিটির সদৃশ হয়, তবে একটি কারখানা পদ্ধতি তৈরির বিষয়টি বিবেচনা করুন যা আপনার বার অবজেক্টের থেকে স্বাধীনভাবে পরীক্ষা করা যেতে পারে:

public Bar createBar(MockedObject mockedObject) {
    Object dependency = mockedObject.someMethod();
    // ...more logic that used to be in Bar constructor
    return new Bar(dependency);
}

যদি এই রিফ্যাক্টরিং খুব কঠিন হয় তবে রিসেট () ব্যবহার করা প্রায় কাজ। তবে আসুন পরিষ্কার হয়ে উঠুন - এটি নির্দেশ করে যা আপনার কোডটি খারাপভাবে ডিজাইন করা হয়েছে।

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