মকিতো ব্যবহার করে কোনও শ্রেণীর সদস্যের ভেরিয়েবলগুলি উপহাস করা


136

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

ধরুন আমার এর মতো দুটি ক্লাস রয়েছে -

public class First {

    Second second ;

    public First(){
        second = new Second();
    }

    public String doSecond(){
        return second.doSecond();
    }
}

class Second {

    public String doSecond(){
        return "Do Something";
    }
}

ধরা যাক আমি পরীক্ষা First.doSecond()পদ্ধতিতে ইউনিট পরীক্ষা লিখছি । তবে, ধরুন, আমি Second.doSecond()এভাবে মক ক্লাস করতে চাই। আমি এটি করতে মকিতো ব্যবহার করছি।

public void testFirst(){
    Second sec = mock(Second.class);
    when(sec.doSecond()).thenReturn("Stubbed Second");

    First first = new First();
    assertEquals("Stubbed Second", first.doSecond());
}

আমি দেখছি যে উপহাস কার্যকর হয় না এবং দৃ the়তা ব্যর্থ হয়। আমি যে ক্লাসটি পরীক্ষা করতে চাই তার কোনও সদস্যের ভেরিয়েবলকে উপহাস করার কোনও উপায় নেই? ?

উত্তর:


86

আপনাকে সদস্য ভেরিয়েবলগুলি অ্যাক্সেস করার একটি উপায় সরবরাহ করতে হবে যাতে আপনি একটি উপহাসের মধ্যে পাস করতে পারেন (সর্বাধিক সাধারণ উপায়গুলি সেটার পদ্ধতি বা একটি প্যারামিটার গ্রহণকারী কনস্ট্রাক্টর হবে)।

যদি আপনার কোড এটি করার কোনও উপায় না দেয় তবে এটি টিডিডি (টেস্ট চালিত বিকাশ) এর জন্য ভুলভাবে ফ্যাক্টর করে।


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

2
একটি পরীক্ষার কনফিগারেশন সহ একটি নির্ভরতা ইনজেকশন কাঠামো ব্যবহার করুন। আপনি যে ইন্টিগ্রেশন পরীক্ষার চেষ্টা করছেন সেটি সিকোয়েন্স ডায়াগ্রাম আঁকুন। আপনি যে বস্তুগুলিকে প্রকৃতপক্ষে নিয়ন্ত্রণ করতে পারেন সেগুলির সিকোয়েন্স ডায়াগ্রামের ফ্যাক্টর। এর অর্থ হ'ল যদি আপনি এমন কোনও ফ্রেমওয়ার্ক শ্রেণীর সাথে কাজ করছেন যার উপরের উপরে নির্ভর করে নির্ভর অবজেক্ট অ্যান্টি-প্যাটার্ন রয়েছে তবে সিকোয়েন্স ডায়াগ্রামের ক্ষেত্রে আপনাকে অবজেক্ট এবং এর খারাপভাবে-ফ্যাক্টার্ড সদস্যকে একটি একক হিসাবে বিবেচনা করা উচিত। এটিকে আরও পরীক্ষামূলক করে তুলতে আপনার নিয়ন্ত্রণ করা কোনও কোডের ফ্যাক্টরিং সামঞ্জস্য করতে প্রস্তুত হন।
কিট্টলিস্ট

9
প্রিয় @ কিত্তলিস্ট, হ্যাঁ সম্ভবত এটি টিডিডি দৃষ্টিকোণ বা কোনও ধরণের যৌক্তিক দৃষ্টিকোণ থেকে ভুল। তবে কখনও কখনও কোনও বিকাশকারী এমন স্থানে কাজ করে যেখানে কিছুই বোঝা যায় না এবং কেবল একটির কাছে লক্ষ্যমাত্র হ'ল আপনি নির্ধারিত গল্পগুলি সম্পূর্ণ করে চলে যান। হ্যাঁ, এটি ভুল, এটি কোনও অর্থবোধ করে না, অ-যোগ্যতাসম্পন্ন লোকেরা মূল সিদ্ধান্ত এবং সমস্ত কিছু গ্রহণ করে। সুতরাং, দিনের শেষে, অ্যান্টি-প্যাটার্নগুলি অনেকটা জিতে।
আমানাস

1
আমি এটি সম্পর্কে কৌতূহল, কোনও শ্রেণির সদস্যের যদি বাহ্যিক থেকে সেট করার কোনও কারণ না থাকে তবে কেন এটির পরীক্ষার উদ্দেশ্যে আমরা একটি সেটার তৈরি করব? এখানে 'সেকেন্ড' ক্লাসটি কল্পনা করুন বাস্তবে একটি ফাইলসিস্টেম ম্যানেজার বা সরঞ্জাম, যা পরীক্ষার জন্য অবজেক্ট তৈরির সময় শুরু হয়েছিল। প্রথম শ্রেণির পরীক্ষা করার জন্য এবং এটিকে অ্যাক্সেসযোগ্য করার শূন্য কারণ হিসাবে আমার কাছে এই ফাইলসিস্টেম ম্যানেজারকে উপহাস করতে ইচ্ছে করার সমস্ত কারণ রয়েছে। আমি পাইথনে এটি করতে পারি, তবে মকিতো দিয়ে কেন নয়?
জাঙ্গদার

65

আপনি যদি আপনার কোড পরিবর্তন করতে না পারেন তবে এটি সম্ভব নয়। তবে আমি নির্ভরতা ইনজেকশন পছন্দ করি এবং মকিতো এটি সমর্থন করে:

public class First {    
    @Resource
    Second second;

    public First() {
        second = new Second();
    }

    public String doSecond() {
        return second.doSecond();
    }
}

আপনার পরীক্ষা:

@RunWith(MockitoJUnitRunner.class)
public class YourTest {
   @Mock
   Second second;

   @InjectMocks
   First first = new First();

   public void testFirst(){
      when(second.doSecond()).thenReturn("Stubbed Second");
      assertEquals("Stubbed Second", first.doSecond());
   }
}

এটি খুব সুন্দর এবং সহজ।


2
আমি মনে করি এটি অন্যগুলির চেয়ে ভাল উত্তর কারণ ইনজেক্টমকস।
সুডোকোডার

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

9
@ রিসোর্স কি ?
ইগোরগানাপলস্কি

3
@ আইগোরগানাপলস্কি @ রিসোর্স জাভা স্প্রিং ফ্রেমওয়ার্ক দ্বারা তৈরি / ব্যবহৃত একটি টিকা। এটি স্প্রিংকে নির্দেশ করার উপায় এটি একটি সিম / বস্তু যা স্প্রিং দ্বারা পরিচালিত হয়। stackoverflow.com/questions/4093504/resource-vs-autowired baeldung.com/spring-annotations-resource-inject-autowire এটা একটা mockito জিনিস নয়, কিন্তু কারণ এটি অ পরীক্ষামূলক ক্লাসে ব্যবহার করা হয় তার মধ্যে ব্যঙ্গ করা হয়েছে পরীক্ষা।
গ্রিজ.কেভ

আমি এই উত্তর বুঝতে পারি না। আপনি বলছেন যে এটি সম্ভব নয় তবে আপনি এটি দেখানো সম্ভব? এখানে ঠিক কী সম্ভব নয়?
সোনার নাম

35

আপনি যদি আপনার কোডটি ঘনিষ্ঠভাবে দেখেন তবে আপনি দেখতে পাবেন যে secondআপনার পরীক্ষার সম্পত্তিটি এখনও Secondএকটি উপহাসের নয়, (আপনি আপনার কোডটিতে উপহাসটি পাস করবেন না first)।

সহজ উপায় জন্য সেটার তৈরি করতে হবে secondযে Firstবর্গ এবং এটি উপহাস স্পষ্টভাবে পাস।

এটার মত:

public class First {

Second second ;

public First(){
    second = new Second();
}

public String doSecond(){
    return second.doSecond();
}

    public void setSecond(Second second) {
    this.second = second;
    }


}

class Second {

public String doSecond(){
    return "Do Something";
}
}

....

public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");


First first = new First();
first.setSecond(sec)
assertEquals("Stubbed Second", first.doSecond());
}

আর একটি হতে হবে এর কনস্ট্রাক্টর প্যারামিটার Secondহিসাবে একটি উদাহরণ পাস Firstকরা।

আপনি যদি কোডটি সংশোধন করতে না পারেন তবে আমি মনে করি প্রতিফলনটি ব্যবহার করার একমাত্র বিকল্প হবে:

public void testFirst(){
    Second sec = mock(Second.class);
    when(sec.doSecond()).thenReturn("Stubbed Second");


    First first = new First();
    Field privateField = PrivateObject.class.
        getDeclaredField("second");

    privateField.setAccessible(true);

    privateField.set(first, sec);

    assertEquals("Stubbed Second", first.doSecond());
}

তবে আপনি সম্ভবত এটি করতে পারেন, যেহেতু আপনি নিয়ন্ত্রণ করেন না এমন কোডে পরীক্ষা করা বিরল (যদিও এটি এমন কোনও দৃশ্যের কল্পনা করতে পারে যেখানে আপনাকে কোনও বাহ্যিক গ্রন্থাগার পরীক্ষা করতে হবে কারণ এটি লেখক করেন নি :))


বুঝেছি. আমি সম্ভবত আপনার প্রথম পরামর্শ দিয়ে যাব।
আনন্দ হেমমিগে

কেবল কৌতূহলী, এমন কোনও উপায় বা এপিআই রয়েছে যা সম্পর্কে আপনি অবগত আছেন যা অ্যাপ্লিকেশন স্তর বা প্যাকেজ স্তরে কোনও অবজেক্ট / পদ্ধতিটিকে উপহাস করতে পারে। ? আমি অনুমান করছি যে আমি যা বলছি তা উপরের উদাহরণে যখন আমি 'দ্বিতীয়' অবজেক্টটিকে উপহাস করি তখন কী এমন উপায় আছে যা পরীক্ষার জীবনচক্রের মাধ্যমে ব্যবহৃত দ্বিতীয়টির প্রতিটি উদাহরণকে ওভাররাইড করতে পারে? ?
আনন্দ হেমমিগে

@ আনানহেমমিগ আসলে দ্বিতীয়টি (কনস্ট্রাক্টর) পরিষ্কার, কারণ এটি অনিবার্য `সেকেন্ডের উদাহরণ তৈরি করা এড়িয়ে যায়। আপনার ক্লাসগুলি সেভাবে সুন্দরভাবে ডিকোপল হয়ে যায়।
24-30

10
মকিতো আপনাকে আপনার ভোগ্যগুলি ব্যক্তিগত ভেরিয়েবলগুলিতে ইনজেক্ট করতে দেওয়ার জন্য কয়েকটি দুর্দান্ত টিকা প্রদান করে। সঙ্গে টীকা দ্বিতীয় @Mockএবং annotate প্রথম @InjectMocksএবং সূচনাকারী মধ্যে instantiate প্রথম। মকিতো প্রথম বারের মতো দ্বিতীয় মোককে ইনজেক্ট করার জন্য জায়গা খুঁজে বার করার জন্য ব্যক্তিগত ক্ষেত্রগুলির সাথে মেলে এমন ব্যক্তিগত ক্ষেত্র নির্ধারণের মাধ্যমে স্বয়ংক্রিয়ভাবে সেরা করবে।
ঝাড়িক

@Mock1.5 এর কাছাকাছি ছিল (সম্ভবত আগে, আমি নিশ্চিত নই)। 1.8.3 @InjectMocksপাশাপাশি চালু @Spyএবং @Captor
ঝাড়িক

7

আপনি যদি সদস্যের পরিবর্তনশীলটি পরিবর্তন করতে না পারেন তবে এর অন্য উপায়টি হ'ল পাওয়ারমোকিট এবং কল ব্যবহার করা

Second second = mock(Second.class)
when(second.doSecond()).thenReturn("Stubbed Second");
whenNew(Second.class).withAnyArguments.thenReturn(second);

এখন সমস্যাটি হ'ল নতুন সেকেন্ডের যে কোনও কল একই বিদ্রূপযুক্ত উদাহরণটি ফিরে আসবে। তবে আপনার সাধারণ ক্ষেত্রে এটি কাজ করবে।


6

আমার একই সমস্যা ছিল যেখানে একটি ব্যক্তিগত মূল্য সেট করা হয়নি কারণ মকিতো সুপার কনস্ট্রাক্টরকে কল করে না। এখানে আমি প্রতিবিম্বের সাথে উপহাসকে কীভাবে বাড়িয়ে তুলছি।

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

public class TestUtils {
    // get a static class value
    public static Object reflectValue(Class<?> classToReflect, String fieldNameValueToFetch) {
        try {
            Field reflectField  = reflectField(classToReflect, fieldNameValueToFetch);
            reflectField.setAccessible(true);
            Object reflectValue = reflectField.get(classToReflect);
            return reflectValue;
        } catch (Exception e) {
            fail("Failed to reflect "+fieldNameValueToFetch);
        }
        return null;
    }
    // get an instance value
    public static Object reflectValue(Object objToReflect, String fieldNameValueToFetch) {
        try {
            Field reflectField  = reflectField(objToReflect.getClass(), fieldNameValueToFetch);
            Object reflectValue = reflectField.get(objToReflect);
            return reflectValue;
        } catch (Exception e) {
            fail("Failed to reflect "+fieldNameValueToFetch);
        }
        return null;
    }
    // find a field in the class tree
    public static Field reflectField(Class<?> classToReflect, String fieldNameValueToFetch) {
        try {
            Field reflectField = null;
            Class<?> classForReflect = classToReflect;
            do {
                try {
                    reflectField = classForReflect.getDeclaredField(fieldNameValueToFetch);
                } catch (NoSuchFieldException e) {
                    classForReflect = classForReflect.getSuperclass();
                }
            } while (reflectField==null || classForReflect==null);
            reflectField.setAccessible(true);
            return reflectField;
        } catch (Exception e) {
            fail("Failed to reflect "+fieldNameValueToFetch +" from "+ classToReflect);
        }
        return null;
    }
    // set a value with no setter
    public static void refectSetValue(Object objToReflect, String fieldNameToSet, Object valueToSet) {
        try {
            Field reflectField  = reflectField(objToReflect.getClass(), fieldNameToSet);
            reflectField.set(objToReflect, valueToSet);
        } catch (Exception e) {
            fail("Failed to reflectively set "+ fieldNameToSet +"="+ valueToSet);
        }
    }

}

তারপরে আমি ক্লাসটি এই জাতীয় প্রাইভেট ভেরিয়েবল দিয়ে পরীক্ষা করতে পারি। শ্রেণিকক্ষগুলিতে গভীরভাবে ঠাট্টা করার জন্য এটি কার্যকর যে আপনার পাশাপাশি কোনও নিয়ন্ত্রণও নেই।

@Test
public void testWithRectiveMock() throws Exception {
    // mock the base class using Mockito
    ClassToMock mock = Mockito.mock(ClassToMock.class);
    TestUtils.refectSetValue(mock, "privateVariable", "newValue");
    // and this does not prevent normal mocking
    Mockito.when(mock.somthingElse()).thenReturn("anotherThing");
    // ... then do your asserts
}

আমি এখানে আমার আসল প্রকল্প থেকে পৃষ্ঠাতে আমার কোডটি পরিবর্তন করেছি। একটি সংকলন সমস্যা হতে পারে বা দুটি। আমি মনে করি আপনি সাধারণ ধারণা পেয়েছেন। কোডটি দখল করতে দ্বিধা বোধ করুন এবং আপনি যদি এটি দরকারী মনে করেন তবে এটি ব্যবহার করুন।


আপনি কি সত্যই ইউজকেস দিয়ে আপনার কোডটি ব্যাখ্যা করতে পারেন? পাবলিক ক্লাস টুমোকারের মতো () {বেসরকারী ক্লাসঅবজেক্ট ক্লাসঅবজেক্ট; Class যেখানে ক্লাসঅজেক্ট বস্তুর প্রতিস্থাপনের সমান।
জেস্পার ল্যানখোরস্ট

আপনার উদাহরণে, যদি ToBeMocker দৃষ্টান্ত = নতুন ToBeMocker (); এবং ClassObject someNewInstance = নতুন ClassObject () {@ ওভাররাইড // বাহ্যিক নির্ভরতার মতো কিছু}; তারপরে TestUtils.refelctSetValue (উদাহরণস্বরূপ, "ClassObject", SomeNewInstance); মনে রাখবেন যে উপহাস করার জন্য আপনি কী ওভাররাইড করতে চান তা নির্ধারণ করতে হবে। বলুন যে আপনার কাছে একটি ডাটাবেস রয়েছে এবং এই ওভাররাইডটি একটি মান ফেরত দেবে যাতে আপনার নির্বাচনের প্রয়োজন হয় না। অতি সম্প্রতি আমার কাছে একটি সার্ভিস বাস ছিল যা আমি বার্তাটি প্রক্রিয়া করতে চাইনি তবে এটি এটি পেয়েছে তা নিশ্চিত করতে চেয়েছিলাম। এইভাবে, আমি ব্যক্তিগতভাবে বাসের উদাহরণটি এই উপায়ে সহায়ক?
ডেভ

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

1

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

আপনি যদি কোডটিকে আরও পরীক্ষামূলক করে তোলার জন্য পরিবর্তন করতে না পারেন তবে পাওয়ারমক: https://code.google.com/p/powermock/

পাওয়ারমকটি অতিরিক্ত কার্যকারিতা সরবরাহ করে মকিতোকে প্রসারিত করে (যাতে আপনাকে নতুন মক ফ্রেমওয়ার্ক শিখতে হবে না)। এটিতে একজন কনস্ট্রাক্টরকে একটি মোক উপার্জন করার ক্ষমতা অন্তর্ভুক্ত রয়েছে। শক্তিশালী, তবে কিছুটা জটিল - তাই এটিকে ন্যায়বিচারের সাথে ব্যবহার করুন।

আপনি অন্য মক রানার ব্যবহার করেন। এবং আপনাকে নির্মাণ করতে হবে যে ক্লাস প্রস্তুত করতে হবে। (দ্রষ্টব্য যে এটি একটি সাধারণ গোটচা - বর্গ প্রস্তুত করুন যা নির্মাণকারীকে ডেকেছে, নির্মাণকৃত শ্রেণিকে নয়)

@RunWith(PowerMockRunner.class)
@PrepareForTest({First.class})

তারপরে আপনার পরীক্ষার সেট আপে, আপনি যখন নতুন পদ্ধতিটি ব্যবহারকারীর কাছে একটি মক ফিরিয়ে দিতে ব্যবহার করতে পারেন

whenNew(Second.class).withAnyArguments().thenReturn(mock(Second.class));

0

হ্যাঁ, এটি করা যেতে পারে, নিম্নলিখিত পরীক্ষার শো হিসাবে (জেমকিত মকিং এপিআই, যা আমি বিকাশ করি তা দিয়ে লেখা):

@Test
public void testFirst(@Mocked final Second sec) {
    new NonStrictExpectations() {{ sec.doSecond(); result = "Stubbed Second"; }};

    First first = new First();
    assertEquals("Stubbed Second", first.doSecond());
}

মকিতো দিয়ে তবে এ জাতীয় পরীক্ষা লেখা যায় না। এটি মকিতোতে যেভাবে উপহাসকে প্রয়োগ করা হয়েছে তার কারণেই, যেখানে উপহাস করার জন্য শ্রেণির একটি সাবক্লাস তৈরি করা হয়েছে; কেবলমাত্র এই "মক" সাবক্লাসের উদাহরণগুলিতে বিদ্রূপাত্মক আচরণ থাকতে পারে, তাই আপনার পরীক্ষা করা কোড অন্য কোনও উদাহরণের পরিবর্তে সেগুলি ব্যবহার করা দরকার।


3
জোকিমিট মকিতোর চেয়ে ভাল কিনা তা প্রশ্ন ছিল না, বরং এটি মকিতোতে কীভাবে করবেন। প্রতিযোগিতার আবর্জনার সুযোগের পরিবর্তে আরও ভাল পণ্য তৈরি করতে আটকে থাকুন!
TheZuck

8
মূল পোস্টারটি কেবলমাত্র বলে যে তিনি মকিতো ব্যবহার করছেন; এটি কেবল ইঙ্গিত করা হয়েছে যে মকিতো একটি স্থির এবং কঠোর প্রয়োজনীয়তা তাই জেএমকিত এই পরিস্থিতিটি পরিচালনা করতে পারে এমন ইঙ্গিতটি অনুচিত নয়।
বোম্বে

0

আপনি যদি মকিতো স্প্রিং থেকে রিফ্লেকশনস্টেস্টিলের বিকল্প চান তবে ব্যবহার করুন

Whitebox.setInternalState(first, "second", sec);

স্ট্যাক ওভারফ্লোতে স্বাগতম! অন্যান্য উত্তরগুলি রয়েছে যা ওপির প্রশ্ন সরবরাহ করে এবং এগুলি বহু বছর আগে পোস্ট করা হয়েছিল। উত্তর পোস্ট করার সময়, দয়া করে নিশ্চিত হন যে আপনি কোনও নতুন সমাধান যুক্ত করেছেন, বা যথেষ্ট উত্তম ব্যাখ্যা, বিশেষত পুরানো প্রশ্নের উত্তর দেওয়ার সময় বা অন্যান্য উত্তরের বিষয়ে মন্তব্য করার সময়।
help-info.de
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.