2017-01-03 14 views
1

テストしたいSpring Batch用のファイルハンドラがあります。SpringApplication.runをどうやって模擬するのですか

SpringApplication.run()は、渡された引数を検証したい静的メソッドです。

これはPowerMockのパスを下げる必要があることを意味しますか、これをテストするためのSpringFrameworkには何かがありますか?私は何をしないのです

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

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; 
} 

私のテストクラスが動作していないようだ、次のアノテーションを持っていますか?

投げた例外は次のとおりです。

java.lang.IllegalStateException:名前org.springframework.boot.SpringApplicationでクラスを変換に失敗しました。理由:@PrepareForTest(SpringApplication.class)が処理されるとき、これが発生し org.springframework.web.context.support.StandardServletEnvironment

を見つけることができません。私はSpring Batchアプリケーションをテストしているので、Web環境はなく、私も追加しました。

@SpringBootTest(webEnvironment=WebEnvironment.NONE) 

答えて

1

この問題は、pom.xmlにエントリがないために発生していました。バッチアプリケーションでのみ動作し、Webまたはサーブレットがないため、SpringFrameworkで少し不満ですこのテストでのコンポーネント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 Applicationでテストしています。このテストを簡略化するためにコンテキストをロードする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; 
    } 
} 

そしてここSpringApplication.runをあざけるIdeallingテストクラス

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

あなたのテストでargsを検証したい1.if、あなたが方法handleFile(file)のコードを呼び出し元にそれを返す必要があり、現在、あなたがやっている - (メソッドのシグネチャを変更することができる場合)return null;を、代わりにあなたは引数を返す必要があります。

私は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テストで組み込まれているので、コードをリファクタリングして静的メソッドを呼び出すことができれば、非静的メソッドをモックして最終的に静的呼び出しをモックすることができます。 @MockBean注釈はSpring Testの一部です。春のバッチでSpringApplication.runのモック4.If

ジョブを実行しているが、単に、その後目的はapplication.propertiesspring.batch.job.enabled=false、言うことによって達成することができ、コンテキストを初期化しないのと同じです。あなたのユニットテストは、SpringApplication.runへの実際の呼び出しが完了するまで待たなければなりませんが、ジョブはキックオフされません。

リファクタリングは、常に機能的に正しいというようなフレームワークの限界を克服するためにリファクタリングすることを躊躇しないに加えて、あなたのコードのユニットがテスト可能にするために奨励されます。

希望すると助かります!

+0

は、私が何をしたいのかでていますが、それはそのテスト可能なように、私は異なり、このクラスをarchitecturingする必要があることを意味するものではありません。私のテストクラスから、次の注釈がありますが、上記の例外はまだあります。 @RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(SpringRunner.class) (SpringApplication.class)@PrepareForTest @SpringBootTest(webEnvironment = WebEnvironment.NONE) @TestPropertySource(プロパティが= { "spring.batch.job.enabled = false "}) –

関連する問題