2017-01-03 32 views
1

我有一個我想測試的Spring Batch的文件處理程序。我如何模擬SpringApplication.run

SpringApplication.run()是,我想驗證傳遞給它的參數的靜態方法。

這是否意味着我需要下井PowerMock路徑或者是有什麼在springframework的,使我對此進行測試?

public File handleFile(File file) { 

    // Start the Batch Process and set the inputFile parameter 
    String[] args = {"--inputFile=" + file.getAbsolutePath()}; 
    SpringApplication.run(InitialFileBatchApplication.class, args); 

    return null; 
} 

我測試類具有以下注釋這似乎並不奏效:

@RunWith(PowerMockRunner.class) 
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class) 
@SpringBootTest 
@PrepareForTest(SpringApplication.class) 

我缺少什麼?

越來越引發的異常是:

java.lang.IllegalStateException:無法用名org.springframework.boot.SpringApplication改造類。原因:找不到 org.springframework.web.context.support.StandardServletEnvironment

@PrepareForTest(SpringApplication.class)處理髮生這種情況。我正在測試Spring Batch應用程序,所以沒有Web環境,我也添加了。

@SpringBootTest(webEnvironment=WebEnvironment.NONE) 

回答

1

由於我遇到的異常,這個問題是由於pom.xml中缺少條目導致的,這使我對SpringFramework感到沮喪,因爲我只在批處理應用程序中工作,並且沒有web或servlet組件在這個測試中。缺少的pom條目是。

<dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-web</artifactId> 
    </dependency> 

我有其他的泉水依賴條件是

<dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-batch</artifactId> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-test</artifactId> 
     <scope>test</scope> 
    </dependency> 

爲了驗證這一點,我確實需要PowerMock的方法與外在的一些方法,這樣我可以測試他們,即使我正在使用Spring應用程序進行測試,我能夠排除加載上下文以簡化此測試的SpringRunner。下面是我的實現類以及測試它的測試類。

import java.io.File; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.boot.SpringApplication; 

public class InitialFileInputFileHandler { 

    private Logger logger = LoggerFactory.getLogger(InitialFileInputFileHandler.class); 

    /** 
    * Handles the Initial Client files that get put into the input directory that match the pattern 
    * defined in initialFileListenerApplicationContext.xml 
    * @param file - The file 
    * @return 
    */ 

    public File handleFile(File file) { 

     logger.info("Got the Initial Client file: " + file.getAbsolutePath() + " start Batch Processing"); 

     // Start the Batch Process and set the inputFile parameter 
     String[] args = buildArguments(file); 

     SpringApplication.run(InitialFileBatchApplication.class, args); 

     // Whatever we return is written to the outbound-channel-adapter. 
     // Returning null will not write anything out and we do not need an outbound-channel-adapter 
     return null; 
    } 

    protected String[] buildArguments(File file) { 
    String[] args = {"--inputFile=" + file.getAbsolutePath()}; 
    return args; 
    } 
} 

而這裏的測試類

import static org.mockito.Mockito.*; 
import static org.hamcrest.Matchers.*; 
import static org.hamcrest.MatcherAssert.*; 

import java.io.File; 

import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.Mock; 
import org.mockito.Mockito; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 
import org.springframework.boot.SpringApplication; 

// This test class must test static methods. One way to do that is with PowerMock. 

// Testing with static methods so we have to run with the PowerMockRunner. 
@RunWith(PowerMockRunner.class) 
// The static method that we want to test is in the SpringApplication class so 
// by using PowerMock we have to prepare this class for testing. 
@PrepareForTest({SpringApplication.class}) 

// If you wanted to load a SpringContext you'd have to include the SpringRunner. 
// Since our Runner is PowerMockRunner, we still have to setup the spring context, so 
// you setup the SpringRunner as the delegate. 
//@PowerMockRunnerDelegate(SpringRunner.class) 
public class InitialFileInputFileHandlerTest { 

    // Setup a mockFile so that I can specify what comes back from the getAbsolutiePath method 
    // without actually to have a file on the file system. 
    @Mock File mockFile; 

    private InitialFileInputFileHandler handler; 

    @Before 
    public void setUp() throws Exception { 
    handler = new InitialFileInputFileHandler(); 
    org.mockito.Mockito.when(mockFile.getAbsolutePath()).thenReturn("src/input/fooFile.txt"); 
    } 

    @Test 
    public void testBuildArguments(){ 
    String[] args = handler.buildArguments(mockFile); 
    assertThat(args[0], equalTo("--inputFile=src/input/fooFile.txt")); 
    } 

    @Test 
    public void testHandleFile() throws Exception { 
    // Tell PowerMockito to keep track of my static method calls in the SpringApplication class 
    PowerMockito.mockStatic(SpringApplication.class); 

    // What I expect the argument to be 
    String[] args = {"--inputFile=src/input/fooFile.txt"}; 

    // Call the actual method 
    handler.handleFile(mockFile); 

    // Have to call verifyStatic since its a static method. 
    PowerMockito.verifyStatic(); 

    // One of a few possibilities to test the execution of the static method. 
    //SpringApplication.run(InitialFileBatchApplication.class, args); 
    //SpringApplication.run(Mockito.any(InitialFileBatchApplication.class), eq(args[0])); 
    SpringApplication.run(Mockito.any(Object.class), eq(args[0])); 
    } 

} 
1

正如我分享你的PowerMock厭惡,第一個答案是不幸的是:你已經寫好,現在的方法 - 只能使用PowerMock進行測試。

所以,如果你想測試方法;你必須使用PowerMock。或者你承擔最小風險...並且根本不測試它。

除此之外:我建議將該方法放入某個接口;你只是想防止這個靜態調用給你的麻煩,當你開始測試的是要調用handleFile()其他方法 - 那麼你希望能夠嘲笑該呼叫;以防止內部的靜態調用發生。

0

1.如果您要驗證args在測試中,你需要它返回到呼叫者方法handleFile(file)的代碼,目前你正在做 - return null;,相反,你應該返回ARGS(如果方法簽名是可以改變的)。

我假設handleFile方法是InitialFileBatchApplication類。

@Test 
    public void testHandleFile() { 
     File file = new File("ABC"); 
     String[] response = new InitialFileBatchApplication().handleFile(file); 

     //Verify response here 
    } 

上面實際上會啓動你的工作。

2.如果你想嘲笑 - SpringApplication.run,因爲它是PowerMock是要走的路。你應該在問題中指出你現在設置的錯誤。

3.Mockito內置在Spring Test中,所以如果你可以重構你的代碼讓非靜態方法調用靜態方法,那麼你可以模擬非靜態方法,並最終嘲笑你的靜態調用。 @MockBean註釋是Spring Test的一部分。到不運行作業而只是初始化上下文然後宗旨可以說,在application.propertiesspring.batch.job.enabled=false實現

4.如果嘲諷SpringApplication.run春季批次等同。只有你的單元測試將不得不等待真正的電話 - SpringApplication.run才能完成,但工作不會開始。

總是鼓勵代碼重構,使您的代碼單元可以在功能上正確地進行測試,所以不要猶豫重構來克服框架限制。

希望它有幫助!

+0

Idealling嘲諷SpringApplication.run是我想做的事情,但這並不意味着我應該區別architecturing該類使其可測試。從我的測試課,我現在有以下注釋,但仍然得到上述例外。 @RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(SpringRunner.class) @PrepareForTest(SpringApplication.class) @SpringBootTest(webEnvironment = WebEnvironment.NONE) @TestPropertySource(屬性= {「spring.batch.job.enabled =假「}) –