如何模拟SpringApplication.run



我有一个要测试的Spring Batch的文件处理程序。

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.IollegalStateException:无法转换名为org.springframework.boot.SpringApplication的类。原因:找不到org.springframework.web.context.support.StandardServlet环境

处理@PrepareForTest(SpringApplication.class)时会发生这种情况。我正在测试一个SpringBatch应用程序,所以没有web环境,我还添加了。

@SpringBootTest(webEnvironment=WebEnvironment.NONE)

我和你一样不喜欢PowerMock,不幸的是,第一个答案是:你现在写的方法-是的只能使用PowerMock进行测试。

因此,如果您想测试方法;你必须使用PowerMock。或者你冒最小的风险。。。根本不测试。

除此之外:我建议将该方法放入一些界面中;当您开始测试想要调用handleFile()的其他方法时,您只想防止这个静态调用给您带来麻烦,然后您希望能够模拟该调用;以防止内部发生静态调用。

这个问题是由于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.如果您想在测试中验证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的一部分。

4.如果在spring-batch中模拟SpringApplication.run相当于不运行作业而是简单地初始化上下文,那么可以通过在application.properties中说spring.batch.job.enabled=false来实现目的。只是你的单元测试将不得不等待真正的调用-SpringApplication.run完成,但工作不会开始

代码重构总是被鼓励让你的代码单元在功能上是正确的之外是可测试的,所以不要犹豫重构以克服框架的限制。

希望它能有所帮助!!

相关内容

  • 没有找到相关文章

最新更新