2016-08-25 6 views
5

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

@SpringBootApplication 
public class Application implements CommandLineRunner { 

    private static final Logger log = LoggerFactory.getLogger(Application.class); 

    @Autowired 
    private Reader reader; 

    @Autowired 
    private Writer writer; 

    public static void main(String[] args) { 
     SpringApplication.run(Application.class, args); 
    } 

    @Override 
    public void run(String... args) throws Exception { 

     Assert.notEmpty(args); 

     List<> cities = reader.get("Berlin"); 
     writer.write(cities); 
    } 
} 

यहां मेरी जुनीट टेस्ट क्लास है।

@RunWith(SpringRunner.class) 
@SpringBootTest 
public class CityApplicationTests { 

    @Test 
    public void contextLoads() { 
    } 
} 

अब, Assert.notEmpty() एक तर्क पारित करने के लिए जनादेश। हालांकि, अब, मैं इसके लिए जुनीट टेस्ट लिख रहा हूं। लेकिन, मुझे Assert से निम्नलिखित अपवाद उठाना पड़ता है।

2016-08-25 16:59:38.714 ERROR 9734 --- [   main] o.s.boot.SpringApplication    : Application startup failed 

java.lang.IllegalStateException: Failed to execute CommandLineRunner 
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:801) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE] 
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:782) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE] 
    at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:769) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE] 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE] 
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:111) [spring-boot-test-1.4.0.RELEASE.jar:1.4.0.RELEASE] 
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.boot.test.autoconfigure.AutoConfigureReportTestExecutionListener.prepareTestInstance(AutoConfigureReportTestExecutionListener.java:46) [spring-boot-test-autoconfigure-1.4.0.RELEASE.jar:1.4.0.RELEASE] 
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12] 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12] 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12] 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12] 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12] 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) [.cp/:na] 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na] 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) [.cp/:na] 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678) [.cp/:na] 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na] 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na] 
Caused by: java.lang.IllegalArgumentException: [Assertion failed] - this array must not be empty: it must contain at least 1 element 
    at org.springframework.util.Assert.notEmpty(Assert.java:222) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.util.Assert.notEmpty(Assert.java:234) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at com.deepakshakya.dev.Application.run(Application.java:33) ~[classes/:na] 
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE] 
    ... 32 common frames omitted 

कोई विचार, पैरामीटर को कैसे पास किया जाए?

+2

ईमानदार होने के लिए, क्या आप इसका परीक्षण भी करना चाहते हैं? मैं सिर्फ एक अतिरिक्त प्रोफ़ाइल बनाउंगा, उस प्रोफ़ाइल का उपयोग होने पर बीन को बाहर कर दें, प्रोफ़ाइल को अपने एकीकरण परीक्षणों में करें और किया गया। 'रन()' विधि का परीक्षण करने के लिए यह करना चाहिए कि आपको क्या करना चाहिए, आप हमेशा एक यूनिट टेस्ट लिख सकते हैं, आपको इसके लिए अपना आवेदन शुरू करने की आवश्यकता नहीं है। – g00glen00b

+0

इसके अलावा ... आपने यह नहीं दिखाया कि आप परीक्षण कैसे शुरू कर रहे हैं, जो हमें तर्क देता है कि आप तर्कों को पारित करने का प्रयास कैसे कर रहे हैं। – chrylis

+0

मैंने जुनीट क्लास को अपडेट किया है जहां से एप्लिकेशन को कॉल किया जाता है। – divinedragon

उत्तर

2

मैं affraid कि अपने समाधान एक तरीका है कि आप प्रस्तुत (जब तक आप वसंत के लिए अपने स्वयं के परीक्षण ढांचे को लागू) में काम नहीं करेगा हूँ।

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

हालांकि, अगर आप एक तरह से आपके आवेदन refactor सकता है कि यह परीक्षण करने के लिए संभव हो जाएगा।

मुझे लगता है कि (जब से तुम स्प्रिंग उपयोग कर रहे हैं) सबसे आसान समाधान शुद्ध आदेश पंक्ति तर्क के बजाय वसंत विन्यास गुण का उपयोग कर लागू किया जा सकता। (लेकिन तुम, ध्यान रखें कि यह समाधान "विन्यास तर्क" के लिए नहीं बल्कि इस्तेमाल किया जाना चाहिए किया जाना चाहिए, क्योंकि वह configuration properties तंत्र स्प्रिंग्स का मुख्य उद्देश्य है)

पढ़ना मापदंडों @Value एनोटेशन का उपयोग कर:

@SpringBootApplication 
public class Application implements CommandLineRunner { 

    @Value("${myCustomArgs.customArg1}") 
    private String customArg1; 

    public static void main(String[] args) { 
     SpringApplication.run(Application.class, args); 
    } 

    @Override 
    public void run(String... args) throws Exception { 

     Assert.notNull(customArg1); 
     //... 
    } 
} 

नमूना परीक्षण:

@RunWith(SpringRunner.class) 
@SpringBootTest({"myCustomArgs.customArg1=testValue"}) 
public class CityApplicationTests { 

    @Test 
    public void contextLoads() { 
    } 
} 

और जब अपने आदेश पंक्ति एप्लिकेशन चला बस जोड़ने के अपने कस्टम पैरामीटर:

--myCustomArgs.customArg1=testValue

3

मैं समीकरण से SpringBoot छोड़ना होगा।

आपको बस वसंत बूट के माध्यम से बिना run विधि का परीक्षण करने की आवश्यकता है, क्योंकि आपका लक्ष्य वसंत बूट का परीक्षण नहीं करना है, है ना? मुझे लगता है कि इस परीक्षण का उद्देश्य प्रतिगमन के लिए अधिक है, यह सुनिश्चित करना कि आपका आवेदन हमेशा IllegalArgumentException फेंकता है जब कोई तर्क प्रदान नहीं किया जाता है?

@RunWith(MockitoJUnitRunner.class) 
public class ApplicationTest { 

    @InjectMocks 
    private Application app = new Application(); 

    @Mock 
    private Reader reader; 

    @Mock 
    private Writer writer; 

    @Test(expected = IllegalArgumentException.class) 
    public void testNoArgs() throws Exception { 
     app.run(); 
    } 

    @Test 
    public void testWithArgs() throws Exception { 
     List list = new ArrayList(); 
     list.add("test"); 
     Mockito.when(reader.get(Mockito.anyString())).thenReturn(list); 

     app.run("myarg"); 

     Mockito.verify(reader, VerificationModeFactory.times(1)).get(Mockito.anyString()); 
     Mockito.verify(writer, VerificationModeFactory.times(1)).write(list); 
    } 
} 

मैं रीडर के लिए mocks सुई Mockito इस्तेमाल किया और लेखक: अच्छे पुराने इकाई परीक्षण अभी भी एक भी विधि का परीक्षण करने के काम करता है

<dependency> 
    <groupId>org.mockito</groupId> 
    <artifactId>mockito-all</artifactId> 
    <version>1.9.0</version> 
    <scope>test</scope> 
</dependency> 
+0

अपने बिंदु से सहमत हैं। हालांकि, मैं कार्यात्मक परीक्षण परिप्रेक्ष्य से अधिक देख रहा था और कमांड लाइन से अलग-अलग मान प्रदान करके विशेष रूप से कोड के निष्पादन का परीक्षण करना चाहता था। ऐसा लगता है कि ऐसा करने का कोई तरीका नहीं है। – divinedragon

4

मैं JUnit परीक्षण बनाने के लिए एक रास्ता खोजने में कामयाब रहे कि मेरे परीक्षण में ApplicationContext इंजेक्शन करके और आवश्यक पैरामीटर के साथ कमांडलाइनरनर को कॉल करके स्प्रिंगबूट के साथ ठीक काम किया।

अंतिम कोड कि तरह लग रहा है:

package my.package. 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.CommandLineRunner; 
import org.springframework.boot.test.context.SpringBootTest; 
import org.springframework.context.ApplicationContext; 
import org.springframework.test.context.junit4.SpringRunner; 

@RunWith(SpringRunner) 
@SpringBootTest 
class AsgardBpmClientApplicationIT { 

    @Autowired 
    ApplicationContext ctx; 

    @Test 
    void testRun() { 
     CommandLineRunner runner = ctx.getBean(CommandLineRunner.class); 
     runner.run ("-k", "arg1", "-i", "arg2"); 
    } 

} 
+0

यह एक अच्छा समाधान है। हालांकि टेस्ट को सार्वजनिक होना जरूरी है। –

0

जैसा कि बताया जा in this answer, स्प्रिंग बूट वर्तमान में रोकना/DefaultApplicationArguments यह का उपयोग करता है को बदलने के लिए एक तरीका प्रदान नहीं करता है। एक प्राकृतिक-बूट-रास्ता जिसे मैंने हल करने के लिए उपयोग किया था, मेरे धावक तर्क को बढ़ाने और कुछ स्वाभाविक गुणों का उपयोग करना था।

पहले, मैं एक गुण घटक बनाया:

@ConfigurationProperties("app") @Component @Data 
public class AppProperties { 
    boolean failOnEmptyFileList = true; 
    boolean exitWhenFinished = true; 
} 

... मेरी धावक में गुण घटक autowired:

@Service 
public class Loader implements ApplicationRunner { 

    private AppProperties properties; 

    @Autowired 
    public Loader(AppProperties properties) { 
     this.properties = properties; 
    } 
    ... 

... और, run में मैं केवल assert'ed जब वह गुण सक्षम होता है, जो सामान्य अनुप्रयोग उपयोग के लिए true पर डिफ़ॉल्ट होता है:

@Override 
public void run(ApplicationArguments args) throws Exception { 
    if (properties.isFailOnEmptyFileList()) { 
     Assert.notEmpty(args.getNonOptionArgs(), "Pass at least one filename on the command line"); 
    } 

    // ...do some loading of files and such 

    if (properties.isExitWhenFinished()) { 
     System.exit(0); 
    } 
} 

कि के साथ, मैं एक इकाई परीक्षण मैत्रीपूर्ण ढंग से निष्पादित करने के लिए उन गुणों tweak कर सकते हैं:

@RunWith(SpringRunner.class) 
@SpringBootTest(properties = { 
     "app.failOnEmptyFileList=false", 
     "app.exitWhenFinished=false" 
}) 
public class InconsistentJsonApplicationTests { 

    @Test 
    public void contextLoads() { 
    } 

} 

मैं exitWhenFinished भाग की जरूरत के बाद से मेरी विशेष धावक सामान्य रूप से System.exit(0) कॉल करता है और इस तरह से बाहर निकलने के लिए एक अर्ध में इकाई परीक्षण छोड़ देता है विफल राज्य।

संबंधित मुद्दे