मैं एक माइक्रोनॉट क्लास का परीक्षण कर रहा हूं जिसमें एक बीन इंजेक्ट किया गया है। अपने परीक्षण में मैं इसे ओवरराइड करने के लिए एक @MockBean वर्ग प्रदान करता हूं। हालांकि, ऐसा लगता है कि माइक्रोनॉट अभी भी वास्तविक निर्भरता को इंजेक्ट करता है।

@MicronautTest
public class ClassUnderTestTest {

    @Inject ClassUnderTest classUnderTest;

    @Test
    public void test() {

    }

    @MockBean
    Dependency dependency() {
        return mock(Dependency.class);
    }

}

मैंने Github पर एक न्यूनतम रेप्रो अपलोड किया है: https://github.com/crummy/micronaut-test-dependencies . वास्तविक निर्भरता एक अपवाद फेंकता है, और परीक्षण भी करता है। मुझे अपने @MockBean के कारण ऐसा होने की उम्मीद नहीं थी।

अगर मैं एनोटेशन को @MockBean(Dependency.class) में बदलता हूं तो मुझे यह त्रुटि मिलती है: Message: No bean of type [di.failure.example.Dependency] exists। यह मेरे लिए और भी अधिक भ्रमित करने वाला लगता है - अब यह मेरी वास्तविक या मेरी नकली निर्भरता का समाधान नहीं करता है?

13
Malcolm Crum 3 नवम्बर 2018, 17:05

1 उत्तर

सबसे बढ़िया उत्तर

यदि आपकी निर्भरता ClassUnderTest में इंटरफ़ेस द्वारा दर्शायी जाती है, तो @MockBean एनोटेशन के साथ नकली बीन इंजेक्ट करना काम करता है। मान लें कि Dependency एक सरल इंटरफ़ेस है जैसे:

package di.failure.example;

public interface Dependency {
    void run();
}

आपका आवेदन DependencyImpl नामक इस इंटरफ़ेस के लिए कार्यान्वयन प्रदान कर सकता है:

package di.failure.example;

import javax.inject.Singleton;

@Singleton
public class DependencyImpl implements Dependency {
    @Override
    public void run() {
        throw new RuntimeException("I don't want this to load!");
    }
}

अब, परीक्षण के उद्देश्य से आप एक नकली को परिभाषित कर सकते हैं जो DependencyImpl को प्रतिस्थापित करता है:

package di.failure.example;

import io.micronaut.test.annotation.MicronautTest;
import io.micronaut.test.annotation.MockBean;
import org.junit.jupiter.api.Test;

import javax.inject.Inject;

import static org.mockito.Mockito.mock;

@MicronautTest
public class ClassUnderTestTest {

    @Inject
    ClassUnderTest classUnderTest;

    @Test
    public void test() {
        classUnderTest.run();
    }

    @MockBean(DependencyImpl.class)
    public Dependency dependency() {
        return mock(Dependency.class);
    }

}

यह परीक्षण निष्पादित होता है और dependency() विधि द्वारा लौटाए गए नकली का उपयोग DependencyImpl के स्थान पर किया जाता है।

@Replaces एनोटेशन का उपयोग करना

जैसा कि Sergio ने टिप्पणी अनुभाग में उल्लेख किया है, आप @Replaces एनोटेशन। निम्नलिखित उदाहरण पर विचार करें:

package di.failure.example;

import io.micronaut.context.annotation.Replaces;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;

import javax.inject.Inject;
import javax.inject.Singleton;

@MicronautTest
public class ClassUnderTestTest {

    @Inject
    ClassUnderTest classUnderTest;

    @Test
    public void test() {
        classUnderTest.run();
    }

    @Replaces(Dependency.class)
    @Singleton
    public static class MockDependency extends Dependency {

        public MockDependency() {
            System.out.println("MockDependency.<init>");
        }

        @Override
        void run() {
            System.out.println("Does not throw any exception...");
        }
    }
}

इस उदाहरण में हमने एक वर्ग MockDependency को परिभाषित किया है और हम माइक्रोनॉट के DI तंत्र को Dependency बीन को MockDependency से बदलने का निर्देश देते हैं। हालाँकि, एक महत्वपूर्ण बात हमें याद रखने की आवश्यकता है - क्योंकि हमारा MockDependency Dependency वर्ग का विस्तार करता है, माता-पिता का निर्माण लागू हो जाता है। आपने प्रश्न में जो उदाहरण दिखाया है वह इस मामले में काम नहीं करेगा, क्योंकि Dependency.<init> फेंकता है RuntimeException और परीक्षण विफल हो जाता है। इस संशोधित उदाहरण में मैंने इस तरह की कक्षा का उपयोग किया है:

package di.failure.example;

import javax.inject.Singleton;

@Singleton
public class Dependency {

    public Dependency() {
        System.out.println("Dependency.<init>");
    }

    void run() {
        throw new RuntimeException("I don't want this to load!");
    }
}

जब मैं परीक्षण चलाता हूं तो यह गुजरता है और मुझे निम्न कंसोल आउटपुट दिखाई देता है:

Dependency.<init>
MockDependency.<init>
Does not throw any exception...

@MockBean की तुलना में मुख्य अंतर यह है कि @Replaces के मामले में आप एक ठोस वर्ग वस्तु का उपयोग कर रहे हैं। वर्कअराउंड के रूप में (यदि हमें वास्तव में मॉकिटो मॉक ऑब्जेक्ट की आवश्यकता है) आंतरिक रूप से एक मॉक बनाना है और इस ऑब्जेक्ट को कॉल करना है, कुछ इस तरह:

@Replaces(Dependency.class)
@Singleton
public class MockDependency extends Dependency {

    private final Dependency delegate;

    public MockDependency() {
        this.delegate = mock(Dependency.class);
    }

    @Override
    void run() {
        delegate.run();
    }
}
17
Szymon Stepniak 4 नवम्बर 2018, 16:37