जावा में अमूर्त वर्ग को JUnit के साथ कैसे परीक्षण करें?


87

मैं JUnit के साथ जावा परीक्षण में नया हूं। मुझे जावा के साथ काम करना है और मैं यूनिट परीक्षणों का उपयोग करना चाहूंगा।

मेरी समस्या यह है: मेरे पास कुछ सार विधियों के साथ एक सार वर्ग है। लेकिन कुछ तरीके हैं जो अमूर्त नहीं हैं। मैं JUnit के साथ इस कक्षा का परीक्षण कैसे कर सकता हूं? उदाहरण कोड (बहुत सरल):

abstract class Car {

    public Car(int speed, int fuel) {
        this.speed = speed;
        this.fuel = fuel;
    }

    private int speed;
    private int fuel;

    abstract void drive();

    public int getSpeed() {
        return this.speed;
    }

    public int getFuel() {
        return this.fuel;
    }
}

मैं परीक्षण getSpeed()और getFuel()कार्य करना चाहता हूं ।

इस समस्या के समान प्रश्न यहाँ है , लेकिन यह JUnit का उपयोग नहीं कर रहा है।

JUnit FAQ सेक्शन में, मुझे यह लिंक मिला , लेकिन मुझे समझ नहीं आया कि लेखक इस उदाहरण के साथ क्या कहना चाहता है। कोड की इस लाइन का क्या अर्थ है?

public abstract Source getSource() ;

4
Mockito का उपयोग करके दो समाधानों के लिए stackoverflow.com/questions/1087339/… देखें ।
ddso 12

क्या परीक्षण के लिए एक और रूपरेखा सीखने का कोई फायदा है? क्या मॉकिटो केवल ज्यूनिट का विस्तार है, या पूरी तरह से अलग परियोजना है?
वास्को

मॉकिटो JUnit की जगह नहीं लेता है। अन्य मॉकिंग फ्रेमवर्क की तरह, यह एक यूनिट टेस्टिंग फ्रेमवर्क के अलावा उपयोग किया जाता है और आपके परीक्षण मामलों में उपयोग करने के लिए नकली ऑब्जेक्ट बनाने में आपकी सहायता करता है।
ddso

जवाबों:


104

यदि आपके पास कक्षा का कोई ठोस कार्यान्वयन नहीं है और विधियाँ staticउनके परीक्षण की बात नहीं है? यदि आपके पास एक ठोस वर्ग है तो आप उन विधियों का परीक्षण कर रहे हैं जो ठोस वर्ग के सार्वजनिक API के भाग के रूप में हैं।

मुझे पता है कि आप क्या सोच रहे हैं "मैं इन तरीकों का परीक्षण नहीं करना चाहता हूं और इसके कारण मैंने अमूर्त वर्ग का निर्माण किया है", लेकिन इसके लिए मेरा काउंटर तर्क यह है कि इकाई परीक्षणों का बिंदु डेवलपर्स को बदलाव करने की अनुमति देना है। परीक्षण चलाते हैं, और परिणामों का विश्लेषण करते हैं। उन परिवर्तनों के हिस्से में आपके अमूर्त वर्ग के तरीकों को ओवरराइड करना शामिल हो सकता है, दोनों protectedऔर public, जिसके परिणामस्वरूप मौलिक व्यवहार परिवर्तन हो सकते हैं। उन परिवर्तनों की प्रकृति के आधार पर यह प्रभावित हो सकता है कि आपका आवेदन अप्रत्याशित, संभवतः नकारात्मक तरीकों से कैसे चलता है। यदि आपके पास इस प्रकार के परिवर्तनों से उत्पन्न होने वाली एक अच्छी इकाई परीक्षण सूट समस्या है, तो विकास के समय में स्पष्ट होना चाहिए।


17
100% कोड कवरेज एक मिथक है। आपके पास अपने सभी ज्ञात परिकल्पनाओं को कवर करने के लिए वास्तव में पर्याप्त परीक्षण होना चाहिए कि आपके आवेदन को कैसे व्यवहार करना चाहिए (अधिमानतः कोड ला टेस्ट ड्रिवेन डेवलपमेंट लिखने से पहले)। मैं वर्तमान में एक बहुत ही कार्यशील टीडीडी टीम पर काम कर रहा हूं और हमारे पास केवल 63% कवरेज है, जैसा कि हमने विकसित किया है। क्या वह अच्छा है? कौन जानता है ?, लेकिन मैं इसे वापस जाने और उस उच्च को बढ़ावा देने की कोशिश करने के लिए समय की बर्बादी पर विचार करूंगा।
nsfyn55

3
ज़रूर। कुछ लोग तर्क देंगे कि यह अच्छे TDD का उल्लंघन है। कल्पना कीजिए कि आप एक टीम में हैं। आप यह धारणा बनाते हैं कि विधि अंतिम है और किसी भी ठोस कार्यान्वयन के लिए परीक्षण नहीं करते हैं। कोई संशोधक को हटा देता है और परिवर्तन करता है जो वंशानुगत पदानुक्रम की एक पूरी शाखा को नीचे गिरा देता है। क्या आप नहीं चाहेंगे कि आपका टेस्ट सूट पकड़े?
nsfyn55

31
मैं असहमत हूं। आप टीडीडी में काम करते हैं या नहीं, आपके अमूर्त वर्ग के ठोस तरीके में कोड होता है, इसलिए, उनके पास परीक्षण होना चाहिए (चाहे उपवर्ग हों या न हों)। इसके अलावा, जावा परीक्षण (सामान्य रूप से) कक्षाओं में इकाई परीक्षण। इसलिए, परीक्षण विधियों में वास्तव में कोई तर्क नहीं है जो कक्षा का हिस्सा नहीं है, बल्कि इसके सुपर क्लास का। उस तर्क के बाद, हमें जावा में किसी भी वर्ग का परीक्षण नहीं करना चाहिए, बिना किसी उप-वर्ग वाली कक्षाओं को छोड़कर। ओवरराइड होने के तरीकों के बारे में, कि जब आप उप-वर्ग के परीक्षण में बदलाव / परिवर्धन की जांच करने के लिए एक परीक्षण जोड़ते हैं।
एथनफ़र

3
@ nsfyn55 क्या होगा अगर ठोस तरीके थे final? मुझे एक ही विधि को कई बार परीक्षण करने का कारण नहीं दिखता है यदि कार्यान्वयन में बदलाव नहीं हो सकता है
डाइऑक्सिन

3
क्या हमें परीक्षण के सार तत्व को लक्षित नहीं करना चाहिए ताकि हम उन्हें सभी कार्यान्वयनों के लिए चला सकें? यदि यह संभव नहीं है, तो हम लिस्कोव का उल्लंघन कर रहे हैं, जिसके बारे में हम जानना चाहते हैं और ठीक करना चाहते हैं। केवल अगर कार्यान्वयन कुछ विस्तारित (संगत) कार्यक्षमता जोड़ता है, तो हमें इसके लिए एक विशिष्ट इकाई परीक्षण (और बस उस अतिरिक्त कार्यक्षमता के लिए) होना चाहिए।
tne

36

एक ठोस वर्ग बनाएं जो अमूर्त वर्ग को विरासत में मिला है और फिर उन कार्यों का परीक्षण करता है जो ठोस वर्ग को सार वर्ग से विरासत में मिला है।


आप क्या करेंगे कि आपके पास १० ठोस वर्ग हैं जो अमूर्त वर्ग का विस्तार करते हैं और इनमें से प्रत्येक ठोस वर्ग सिर्फ १ विधि को लागू करेगा और बता दें कि इन वर्गों में से प्रत्येक के लिए अन्य २ विधियां समान हैं, क्योंकि वे अमूर्त में लागू होती हैं। कक्षा? मेरा मामला यह है कि मैं प्रत्येक उपवर्ग के लिए अमूर्त वर्ग के परीक्षणों को कॉपी-पेस्ट नहीं करना चाहता।
स्कारफेस

12

आपके द्वारा पोस्ट किए गए उदाहरण वर्ग के साथ, यह परीक्षण करने के लिए बहुत अधिक समझ में नहीं आता है getFuel()और getSpeed()चूंकि वे केवल 0 वापस कर सकते हैं (कोई सेटर नहीं हैं)।

हालाँकि, यह मानते हुए कि यह केवल उदाहरण के लिए उदाहरण के लिए एक सरल उदाहरण था, और यह कि आपके पास एब्सट्रैक्ट बेस क्लास में परीक्षण करने के लिए वैध कारण हैं (अन्य में पहले से ही निहितार्थ बताए गए हैं), आप अपना टेस्ट कोड सेट कर सकते हैं ताकि यह एक अनाम बना सके बेस क्लास का उपवर्ग जो सिर्फ अमूर्त तरीकों के लिए डमी (नो-ऑप) कार्यान्वयन प्रदान करता है।

उदाहरण के लिए, TestCaseआप में आप ऐसा कर सकते हैं:

c = new Car() {
       void drive() { };
   };

फिर बाकी तरीकों का परीक्षण करें, जैसे:

public class CarTest extends TestCase
{
    private Car c;

    public void setUp()
    {
        c = new Car() {
            void drive() { };
        };
    }

    public void testGetFuel() 
    {
        assertEquals(c.getFuel(), 0);
    }

    [...]
}

(यह उदाहरण JUnit3 सिंटैक्स पर आधारित है। JUnit4 के लिए, कोड थोड़ा अलग होगा, लेकिन विचार समान है।)


उत्तर के लिए धन्यवाद। हां, मेरा उदाहरण सरल था (और इतना अच्छा नहीं)। यहाँ सभी उत्तरों को पढ़ने के बाद, मैंने डमी क्लास लिखी। लेकिन जैसा कि @ nsfyn55 ने अपने जवाब में लिखा है, मैं इस अमूर्त वर्ग के हर वंशज के लिए टेस्ट लिखता हूं।
वास्को

9

यदि आपको किसी भी तरह से समाधान की आवश्यकता है (उदाहरण के लिए, क्योंकि आपके पास अमूर्त वर्ग के बहुत सारे कार्यान्वयन हैं और परीक्षण हमेशा एक ही प्रक्रिया को दोहराएगा) तो आप एक अमूर्त कारखाना विधि के साथ एक सार परीक्षण वर्ग बना सकते हैं जिसे उसी के क्रियान्वयन से प्राप्त किया जाएगा। परीक्षण वर्ग। यह उदाहरण TestNG के साथ काम करता है या मुझे:

का सार परीक्षण वर्ग Car:

abstract class CarTest {

// the factory method
abstract Car createCar(int speed, int fuel);

// all test methods need to make use of the factory method to create the instance of a car
@Test
public void testGetSpeed() {
    Car car = createCar(33, 44);
    assertEquals(car.getSpeed(), 33);
    ...

का कार्यान्वयन Car

class ElectricCar extends Car {

    private final int batteryCapacity;

    public ElectricCar(int speed, int fuel, int batteryCapacity) {
        super(speed, fuel);
        this.batteryCapacity = batteryCapacity;
    }

    ...

कक्षा ElectricCarTestकी इकाई परीक्षण कक्षा ElectricCar:

class ElectricCarTest extends CarTest {

    // implementation of the abstract factory method
    Car createCar(int speed, int fuel) {
        return new ElectricCar(speed, fuel, 0);
    }

    // here you cann add specific test methods
    ...

5

आप ऐसा कुछ कर सकते हैं

public abstract MyAbstractClass {

    @Autowire
    private MyMock myMock;        

    protected String sayHello() {
            return myMock.getHello() + ", " + getName();
    }

    public abstract String getName();
}

// this is your JUnit test
public class MyAbstractClassTest extends MyAbstractClass {

    @Mock
    private MyMock myMock;

    @InjectMocks
    private MyAbstractClass thiz = this;

    private String myName = null;

    @Override
    public String getName() {
        return myName;
    }

    @Test
    public void testSayHello() {
        myName = "Johnny"
        when(myMock.getHello()).thenReturn("Hello");
        String result = sayHello();
        assertEquals("Hello, Johnny", result);
    }
}

4

मैं एक jUnit आंतरिक वर्ग बनाता हूं जो अमूर्त वर्ग से विरासत में मिला है। यह तत्काल किया जा सकता है और सार वर्ग में परिभाषित सभी तरीकों तक पहुंच है।

public class AbstractClassTest {
   public void testMethod() {
   ...
   }
}


class ConcreteClass extends AbstractClass {

}

3
यह उत्कृष्ट सलाह है। यह एक उदाहरण प्रदान करके सुधार किया जा सकता है, हालांकि। शायद आप जिस वर्ग का वर्णन कर रहे हैं, उसका एक उदाहरण।
SDJMcHattie

2

आप एक अनाम वर्ग को तुरंत लिख सकते हैं और फिर उस कक्षा का परीक्षण कर सकते हैं।

public class ClassUnderTest_Test {

    private ClassUnderTest classUnderTest;

    private MyDependencyService myDependencyService;

    @Before
    public void setUp() throws Exception {
        this.myDependencyService = new MyDependencyService();
        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

आप इस दृष्टिकोण को मॉकिटो के साथ बड़े करीने से जोड़ सकते हैं। देखें यहाँ


2

यह परीक्षण करने का मेरा तरीका प्रत्येक के भीतर काफी सरल है abstractUnitTest.java। मैं बस abUUititest.java में एक वर्ग बनाता हूँ जो अमूर्त वर्ग का विस्तार करता है। और इसे इस तरह से परखें।


0

आप पूरे सार वर्ग का परीक्षण नहीं कर सकते। इस मामले में आपके पास सार विधियां हैं, इसका मतलब यह है कि उन्हें उस वर्ग द्वारा लागू किया जाना चाहिए जो दिए गए सार वर्ग का विस्तार करते हैं।

उस वर्ग में प्रोग्रामर को स्रोत कोड लिखना होगा जो उसके तर्क के लिए समर्पित है।

दूसरे शब्दों में, अमूर्त वर्ग के परीक्षण की कोई संवेदनशीलता नहीं है क्योंकि आप इसके अंतिम व्यवहार की जांच करने में सक्षम नहीं हैं।

यदि आपके पास कुछ अमूर्त वर्ग में अमूर्त विधियों से संबंधित प्रमुख कार्यक्षमता नहीं है, तो बस एक और वर्ग बनाएं जहां अमूर्त विधि कुछ अपवाद फेंक देगी।


0

एक विकल्प के रूप में, आप अमूर्त वर्ग के अंदर तर्क को कवर करने वाले सार परीक्षण वर्ग बना सकते हैं और प्रत्येक उपवर्ग परीक्षण के लिए इसका विस्तार कर सकते हैं। ताकि इस तरह से आप यह सुनिश्चित कर सकें कि इस तर्क का प्रत्येक बच्चे के लिए अलग से परीक्षण किया जाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.