বিমূর্ত ক্লাস পরীক্ষা করতে মকিতো ব্যবহার করা


213

আমি একটি বিমূর্ত ক্লাস পরীক্ষা করতে চাই। অবশ্যই, আমি ম্যানুয়ালি ক্লাস থেকে উত্তরাধিকারসূত্রে একটি মক লিখতে পারি ।

আমি কি আমার উপহাসকে হাতছাড়া করার পরিবর্তে একটি বিদ্রূপ কাঠামো (আমি মকিটো ব্যবহার করছি) ব্যবহার করে এটি করতে পারি? কিভাবে?


2
Mockito হিসাবে 1.10.12 , Mockito সমর্থন গুপ্তচরবৃত্তি / বিমূর্ত শ্রেণীর উপহাস সরাসরি:SomeAbstract spy = spy(SomeAbstract.class);
pesche

6
মকিতো ২.7.১৪ অনুসারে, আপনি বিমূর্ত সংঘর্ষকেও উপহাস করতে পারেন যার মাধ্যমে নির্মাণকারীদের যুক্তিগুলির প্রয়োজন হয়mock(MyAbstractClass.class, withSettings().useConstructor(arg1, arg2).defaultAnswer(CALLS_REAL_METHODS))
গেদিমিনাস রিমসা

উত্তর:


315

নিম্নলিখিত পরামর্শ আপনাকে একটি "বাস্তব" উপশ্রেণী তৈরি ছাড়া বিমূর্ত শ্রেণীর পরীক্ষা - নকল হয় উপশ্রেণী।

ব্যবহার করুন Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS), তারপরে অনুরোধ করা কোনও বিমূর্ত পদ্ধতিকে মক করুন।

উদাহরণ:

public abstract class My {
  public Result methodUnderTest() { ... }
  protected abstract void methodIDontCareAbout();
}

public class MyTest {
    @Test
    public void shouldFailOnNullIdentifiers() {
        My my = Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS);
        Assert.assertSomething(my.methodUnderTest());
    }
}

নোট: এই সমাধান সৌন্দর্য আপনি না যে আছে , বিমূর্ত পদ্ধতি বাস্তবায়ন যতদিন তারা কখনো প্রার্থনা করছে।

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


14
নীচে উল্লিখিত হিসাবে, এটি প্রয়োগ করে না যখন বিমূর্ত শ্রেণি পরীক্ষার জন্য বিমূর্ত পদ্ধতি কল করে, যা প্রায়শই ঘটে থাকে।
রিচার্ড নিকোলস

11
এটি আসলে কাজ করে যখন বিমূর্ত শ্রেণি বিমূর্ত পদ্ধতি কল করে। বিমূর্ত পদ্ধতিগুলি স্তম্ভের জন্য কেবল মকিটো.ওহানের পরিবর্তে doReturn বা do কিছুই না সিনট্যাক্স ব্যবহার করুন এবং যদি আপনি কোনও কংক্রিট কলগুলি স্টাব করেন তবে নিশ্চিত হন যে বিমূর্ত কলগুলি প্রথমে আসে make
গোনেন আই

2
আমি কীভাবে এই ধরণের অবজেক্টের উপর নির্ভরশীলতা ইনজেক্ট করতে পারি (বাস্তব উপায়ে কলিংয়ের বিদ্রূপযুক্ত ক্লাস)?
স্যামুয়েল

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

1
যদি বিমূর্ত শ্রেণি নির্মাতা এক বা একাধিক পরামিতি নেয়?
এসডি

68

যদি আপনাকে কেবল কোনও বিমূর্তে স্পর্শ না করে কয়েকটি কংক্রিটের পদ্ধতি পরীক্ষা করতে হয় তবে আপনি এটি ব্যবহার করতে পারেন CALLS_REAL_METHODS ( মর্টেনের উত্তর দেখুন ), তবে পরীক্ষার অধীনে কংক্রিট পদ্ধতিটি যদি কিছু বিমূর্তি বা প্রয়োগ না করা ইন্টারফেস পদ্ধতিতে কল করে তবে এটি কার্যকর হবে না this - মকিতো অভিযোগ করবে "জাভা ইন্টারফেসে আসল পদ্ধতিতে কল করা যায় না।"

(হ্যাঁ, এটি একটি স্বল্প নকশাকৃত নকশা, তবে কিছু ফ্রেমওয়ার্ক, উদাহরণস্বরূপ টেপস্ট্রি 4, এটিকে আপনার উপর চাপ দিন)

কাজটি হ'ল এই পদ্ধতির বিপরীত হওয়া - সাধারণ উপহাস আচরণ (যেমন, সমস্ত কিছু উপহাস / স্ট্যাবড) ব্যবহার করুন doCallRealMethod()এবং পরীক্ষার অধীনে কংক্রিট পদ্ধতিটি স্পষ্টভাবে কল করতে ব্যবহার করুন । যেমন

public abstract class MyClass {
    @SomeDependencyInjectionOrSomething
    public abstract MyDependency getDependency();

    public void myMethod() {
        MyDependency dep = getDependency();
        dep.doSomething();
    }
}

public class MyClassTest {
    @Test
    public void myMethodDoesSomethingWithDependency() {
        MyDependency theDependency = mock(MyDependency.class);

        MyClass myInstance = mock(MyClass.class);

        // can't do this with CALLS_REAL_METHODS
        when(myInstance.getDependency()).thenReturn(theDependency);

        doCallRealMethod().when(myInstance).myMethod();
        myInstance.myMethod();

        verify(theDependency, times(1)).doSomething();
    }
}

যোগ করার জন্য আপডেট হয়েছে:

অকার্যকর পদ্ধতির জন্য, আপনাকে thenCallRealMethod()পরিবর্তে ব্যবহার করতে হবে, যেমন:

when(myInstance.myNonVoidMethod(someArgument)).thenCallRealMethod();

অন্যথায় মকিতো অভিযোগ করবে "অসম্পূর্ণ স্টাব সনাক্ত হয়েছে।"


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

3
হ্যাঁ, আপনি কিছুতেই অবজেক্টের অবস্থার উপর নির্ভর করতে পারবেন না, কেবল পদ্ধতিতে কোড বলা হচ্ছে।
ডেভিড মলে

ওহ তাই অবজেক্টের পদ্ধতিগুলি রাষ্ট্র থেকে পৃথক হয়ে যায়, দুর্দান্ত।
হেলিক্স

17

আপনি একটি গুপ্তচর ব্যবহার করে এটি অর্জন করতে পারেন (যদিও মকিতো 1.8+ এর সর্বশেষতম সংস্করণটি ব্যবহার করুন)।

public abstract class MyAbstract {
  public String concrete() {
    return abstractMethod();
  }
  public abstract String abstractMethod();
}

public class MyAbstractImpl extends MyAbstract {
  public String abstractMethod() {
    return null;
  }
}

// your test code below

MyAbstractImpl abstractImpl = spy(new MyAbstractImpl());
doReturn("Blah").when(abstractImpl).abstractMethod();
assertTrue("Blah".equals(abstractImpl.concrete()));

14

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

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

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

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

বিকল্প সমাধান হ'ল আপনার পরীক্ষার কেসটি নিজেই বিমূর্ত করা, এসইউটি তৈরির জন্য একটি বিমূর্ত পদ্ধতি সহ (অন্য কথায়, পরীক্ষার ক্ষেত্রে টেম্পলেট পদ্ধতি নকশার প্যাটার্নটি ব্যবহার করা হবে )।


8

একটি কাস্টম উত্তর ব্যবহার করার চেষ্টা করুন।

উদাহরণ স্বরূপ:

import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public class CustomAnswer implements Answer<Object> {

    public Object answer(InvocationOnMock invocation) throws Throwable {

        Answer<Object> answer = null;

        if (isAbstract(invocation.getMethod().getModifiers())) {

            answer = Mockito.RETURNS_DEFAULTS;

        } else {

            answer = Mockito.CALLS_REAL_METHODS;
        }

        return answer.answer(invocation);
    }
}

এটি বিমূর্ত পদ্ধতিগুলির জন্য মোককে ফিরিয়ে দেবে এবং কংক্রিটের পদ্ধতিগুলির জন্য আসল পদ্ধতিটিকে কল করবে।


5

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

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

কেবল শ্রেণীর বৈশিষ্ট্যগুলি ডিফল্ট সূচনা ব্যবহার করে: ব্যক্তিগত তালিকা dep1 = নতুন অ্যারেলিস্ট; ব্যক্তিগত তালিকা Dep2 = নতুন অ্যারেলিস্ট

সুতরাং বাস্তব বস্তু বাস্তবায়ন (উদাহরণস্বরূপ ইউনিট পরীক্ষার শ্রেণিতে অভ্যন্তরীণ শ্রেণীর সংজ্ঞা, বিমূর্ত পদ্ধতিগুলিকে ওভাররাইড করে) এবং সত্যিকারের অবজেক্টটি (যা সঠিক ক্ষেত্রের সূচনাকরণ করে) গুপ্তচরবৃত্তি না করে একটি বিমূর্ত শ্রেণীর উপহাস করার কোনও উপায় নেই।

খুব খারাপ যে কেবল পাওয়ারমক এখানে আরও সহায়তা করবে।


2

ধরে নিচ্ছি যে আপনার পরীক্ষার ক্লাসগুলি একই প্যাকেজে রয়েছে (ভিন্ন উত্সের মূলের অধীনে) আপনার ক্লাসগুলির পরীক্ষার অধীনে আপনি কেবল মক তৈরি করতে পারেন:

YourClass yourObject = mock(YourClass.class);

এবং আপনি যে পদ্ধতিগুলি পরীক্ষা করতে চান সেগুলি কল করুন যেমন আপনি অন্য কোনও পদ্ধতির মতো করেন।

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

এটি যা করছে তা YouClassপ্রতিটি বিমূর্ত পদ্ধতিতে খালি বাস্তবায়ন সরবরাহ করার প্রচেষ্টাটির একটি দৃ concrete় উদাহরণ তৈরি করছে এবং সংরক্ষণ করছে।

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


3
তবে মোক ব্যবহার করা আপনার ক্লাসের কংক্রিটের পদ্ধতিগুলি পরীক্ষা করবে না, বা আমি ভুল করছি? এটি আমি যা চাই না তা নয়।
রিপার 234

1
এটি সঠিক, আপনি যদি বিমূর্ত শ্রেণিতে কংক্রিটের পদ্ধতিগুলি ব্যবহার করতে চান তবে উপরেরগুলি কাজ করবে না।
রিচার্ড নিকোলস

দুঃখিত, আমি প্রত্যাশা সম্পর্কে কিছুটা সম্পাদনা করব, যা আপনি কেবল বিমূর্তকে না বলে প্রতিটি পদ্ধতির জন্য প্রয়োজনীয়।
নিক হল্ট

তবে তারপরেও আপনি আপনার উপহাস পরীক্ষা করছেন, কংক্রিটের পদ্ধতিগুলি নয়।
জোনাটান ক্লিউটিয়ার

2

আপনি আপনার পরীক্ষায় একটি বেনাম শ্রেণীর সাথে বিমূর্ত ক্লাস প্রসারিত করতে পারেন। উদাহরণস্বরূপ (জুনিট 4 ব্যবহার করে):

private AbstractClassName classToTest;

@Before
public void preTestSetup()
{
    classToTest = new AbstractClassName() { };
}

// Test the AbstractClassName methods.

2

মকিতো @Mockটীকা দিয়ে বিমূর্ত বিমূর্ত ক্লাসগুলিকে মঞ্জুরি দেয় :

public abstract class My {

    public abstract boolean myAbstractMethod();

    public void myNonAbstractMethod() {
        // ...
    }
}

@RunWith(MockitoJUnitRunner.class)
public class MyTest {

    @Mock(answer = Answers.CALLS_REAL_METHODS)
    private My my;

    @Test
    private void shouldPass() {
        BDDMockito.given(my.myAbstractMethod()).willReturn(true);
        my.myNonAbstractMethod();
        // ...
    }
}

অসুবিধাটি হ'ল আপনার কনস্ট্রাক্টর পরামিতিগুলির প্রয়োজন হলে এটি ব্যবহার করা যাবে না।


0

আপনি একটি বেনাম শ্রেণি তাত্ক্ষণিকভাবে তৈরি করতে পারেন, আপনার উপহাসগুলি ইনজেকশন করতে পারেন এবং তারপরে সেই শ্রেণিটি পরীক্ষা করতে পারেন।

@RunWith(MockitoJUnitRunner.class)
public class ClassUnderTest_Test {

    private ClassUnderTest classUnderTest;

    @Mock
    MyDependencyService myDependencyService;

    @Before
    public void setUp() throws Exception {
        this.classUnderTest = getInstance();
    }

    private ClassUnderTest getInstance() {
        return new ClassUnderTest() {

            private ClassUnderTest init(
                    MyDependencyService myDependencyService
            ) {
                this.myDependencyService = myDependencyService;
                return this;
            }

            @Override
            protected void myMethodToTest() {
                return super.myMethodToTest();
            }
        }.init(myDependencyService);
    }
}

মনে রাখবেন যে দৃশ্যমানতা অবশ্যই বিমূর্ত শ্রেণীর protectedসম্পত্তির myDependencyServiceজন্য ClassUnderTest


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