PowerMock and Mockito not working for TestNG - mockito

I have a utility class with a static method
public class A {
public static boolean test1(){
// Do something
return true;
}
}
I am trying to mock test1 using Powermockito and using TestNG for testing
#PrepareForTest(A.class)
public class UnitTest{
#Test
public void testTest1() {
PowerMockito.mockStatic(A.class);
when(A.test1()).thenReturn(false);
}
}
https://code.google.com/p/powermock/wiki/TestNG_usage
Describes me to do this way.
However, in "when(A.test1()).thenReturn(false);" it calls the actual method test1() during the Mockito.when setup for test1() method. Hence, I believe the setup is not done right where it cannot recognize Class A as a Mock
Am I doing something wrong here?
My dependencies in pom.xml -
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<scope>test</scope>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
<version>1.6.2</version>
<scope>test</scope>
</dependency>

After the comment from #Damien Beaufils, I tried to google more and finally found a post in the powermock issues; The google group describing the same problem.
The solution is that your test should extend PowerMockTestCase (which is imported from the testng powermock module i.e org.powermock.modules.testng)
More info - code.google.com/p/powermock/issues/detail?id=54#c9

Related

Couldn't load plugin class: com.qmetry.qaf.automation.cucumber.QAFCucumberPlugin. It does not implement cucumber.api.Plugin

I planning to use qaf-cucumber library for scenario outlines testdata with external files.
Repo: https://github.com/qmetry/qaf-cucumber
Branch: cucumber-4
When I run my runner class I'm getting below error: Couldn't load plugin class: com.qmetry.qaf.automation.cucumber.QAFCucumberPlugin. It does not implement cucumber.api.Plugin
pom.xml:
<dependencies>
<dependency><groupId>com.qmetry</groupId><artifactId>qaf</artifactId><version>2.1.15</version></dependency>
<dependency><groupId>com.qmetry</groupId><artifactId>qaf-cucumber</artifactId><version>2.1.15-beta-1</version></dependency>
<dependency><groupId>io.cucumber</groupId><artifactId>cucumber-java</artifactId><version>4.5.1</version></dependency>
<dependency><groupId>io.cucumber</groupId><artifactId>cucumber-junit</artifactId><version>4.5.1</version><scope>test</scope></dependency>
<dependency><groupId>io.cucumber</groupId><artifactId>cucumber-plugin</artifactId><version>5.1.3</version></dependency>
<dependency><groupId>io.cucumber</groupId><artifactId>cucumber-core</artifactId><version>4.5.1</version></dependency>
<dependency><groupId>com.aventstack</groupId><artifactId>extentreports-cucumber4-adapter</artifactId><version>1.0.8</version><scope>compile</scope></dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version><scope>compile</scope></dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version><scope>compile</scope></dependency>
<dependency><groupId>io.cucumber</groupId><artifactId>cucumber-junit</artifactId><version>4.5.1</version><scope>compile</scope></dependency>
<dependency><groupId>net.masterthought</groupId><artifactId>cucumber-reporting</artifactId><version>4.10.0</version></dependency>
</dependencies>
RunnerClass:
import io.cucumber.junit.CucumberOptions;
import io.cucumber.junit.Cucumber;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
#CucumberOptions(
features="src/main/java/Features",
glue={"StepDefs"},
monochrome=true,
plugin = { "pretty", "com.qmetry.qaf.automation.cucumber.QAFCucumberPlugin"}
)
public class JunitRunner {
}
feature file:
#smoke
Scenario Outline: Search Keyword using data from file
Given I am on Google Search Page
When I search for "<searchKey>"
Examples:{'datafile':'resources/testdata.json'}
StepDefs:
import com.qmetry.qaf.automation.step.QAFTestStep;
import com.qmetry.qaf.automation.step.QAFTestStepProvider;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.When;
public class GoogleClass {
#Given("I am on Google Search Page")
#QAFTestStep(description="I am on Google Search Page")
public void iAmOnGoogleSearchPage(){
System.out.println("I am on Google Search Page --- New");
}
#When("^I search for \"([^\"]*)\"$")
#QAFTestStep(description = "I search for {0}")
public void iSearchFor(String s) {
System.out.println("I search for " + s);
}
#QAFTestStep(description="it should have {0} in search results")
public void itShouldHave_inSearchResults(String s) {
System.out.printf("it should have %s in search results\n", s);
}
}
Exception:
cucumber.runtime.CucumberException: Couldn't load plugin class: com.qmetry.qaf.automation.cucumber.QAFCucumberPlugin. It does not implement cucumber.api.Plugin
at cucumber.runtime.formatter.PluginFactory.loadClass(PluginFactory.java:178)
at cucumber.runtime.formatter.PluginFactory.pluginClass(PluginFactory.java:165)
at cucumber.runtime.formatter.PluginFactory.getPluginClass(PluginFactory.java:222)
at cucumber.runtime.formatter.PluginFactory.isStepDefinitionReporterName(PluginFactory.java:205)
at io.cucumber.core.options.RuntimeOptionsBuilder$ParsedPluginData.addPluginName(RuntimeOptionsBuilder.java:218)
at io.cucumber.core.options.RuntimeOptionsBuilder.addPluginName(RuntimeOptionsBuilder.java:73)
at io.cucumber.core.options.CucumberOptionsAnnotationParser.addPlugins(CucumberOptionsAnnotationParser.java:96)
at io.cucumber.core.options.CucumberOptionsAnnotationParser.parse(CucumberOptionsAnnotationParser.java:51)
at io.cucumber.junit.Cucumber.<init>(Cucumber.java:91)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:70)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:37)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:70)
at org.junit.internal.requests.ClassRequest.createRunner(ClassRequest.java:28)
at org.junit.internal.requests.MemoizingRequest.getRunner(MemoizingRequest.java:19)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:50)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
For cucumber-4 support you need to use qaf-cucumber4 dependency instead of qaf-cucumber.
I am able to find everything working with following setup:
POM:
<dependencies>
<dependency>
<groupId>com.qmetry</groupId>
<artifactId>qaf</artifactId>
<version>2.1.15</version>
</dependency>
<dependency>
<groupId>com.qmetry</groupId>
<artifactId>qaf-cucumber4</artifactId>
<version>2.1.15</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>4.8.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>4.8.0</version>
<scope>test</scope>
</dependency>
</dependencies>
Runner:
package com.example;
import io.cucumber.junit.CucumberOptions;
import io.cucumber.junit.Cucumber;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
#CucumberOptions(
features="Features",
glue={"com.example.common"},
monochrome=true,
plugin = {"com.qmetry.qaf.automation.cucumber.QAFCucumberPlugin","pretty"}
)
public class JunitRunner {
}
Feature file:
Feature: Test cucumber
#smoke
Scenario: Search Keyword
Given I am on Google Search Page
When I search for "qaf"
#smoke
#datafile:resources/testdata.json
Scenario Outline: Search Keyword using data from file
Given I am on Google Search Page
When I search for "<searchKey>"
data file:
[
{
"searchKey": "qaf selenium"
},
{
"searchKey": "selenium ecosystem frameworks"
}
]

weld-junit5 4.0.0.CR1 namespace confusion

I'm a bit confused about the namespace usage for #Inject, #Produces etc. with weld-junit5 4.0.0.CR2. I'm toying around with JakartaEE 8 + Java 17 and weld-junit5 3.x got upset so I guess 4.x is the way to go?
The problem is that with a test class like
#EnableWeld
public class TestNotificationDao {
#WeldSetup
public WeldInitiator weld = WeldInitiator.of(NotificationDao.class, NotificationDaoImpl.class, TestNotificationDao.class);
#Inject
private NotificationDao notificationDao;
public TestNotificationDao() {
}
#Produces
static DataSource getDataSource() {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setURL("jdbc:mysql://localhost:3306/sps?useSSL=false");
dataSource.setUser("sps");
dataSource.setPassword("sps");
dataSource.setDatabaseName("sps");
return dataSource;
}
#Test
public void testLoadQueuedNotifications() {
Collection<QueuedNotification> notifications = notificationDao.getQueuedNotifications(1);
assertEquals(1, notifications.size());
}
}
If I use javax.inject.Inject, the notificationDao is null and If I use jakarta.inject.Inject (and Produces), notificationDao is injected but the #javax.inject.Inject private DataSource dataSource inside the NotificationDaoImpl is null.
Solved by moving to the
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>9.1.0</version>
<scope>provided</scope>
</dependency>

How to set up & clean up a resource in Spock for a test suite

I have this code in my JUnit suite:
#RunWith(Suite.class)
#Suite.SuiteClasses({ MyJavaTest.class, MyAnotherJavaTest.class })
public class MyIntegrationSuite {
#BeforeClass
public static void beforeTests() throws Exception {
Container.start();
}
#AfterClass
public static void afterTests() throws Exception {
Container.stop();
}
}
I want to rewrite it to Spock, but I can't find any way to do a global setup, only setupSpec() and setup() which is not enough, since I have multiple specifications and I want to start a Container only once.
I tried leaving the suite as it is and passing Spock specifications to it, but the spock tests are skipped entirely (when I add extends Specifications). It's probably, because Specification has #RunWith(Sputnik) and it doesn't play with #RunWith(Suite), but I'm not sure how to get around that.
Is there any way to do a global setup with Spock or execute Spock specifications from JUnit suite?
My pom.xml (stubs are there, because I'm mixing java and groovy code):
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>${buildhelper.plugin.version}</version>
<executions>
<execution>
<id>add-groovy-test-source</id>
<phase>test</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/src/test/groovy</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>${gmavenplus.plugin.version}</version>
<executions>
<execution>
<goals>
<goal>generateTestStubs</goal>
<goal>compileTests</goal>
<goal>removeTestStubs</goal>
</goals>
</execution>
</executions>
</plugin>
In general, Spock is a JUnit After all (that's why surefire plugin can run it without any additional hassle), so all approaches to the Suites should work, although I haven't used this feature.
In addition, If you have a "heavy" shared resource, then you might try the following approach:
abstract class SharedResourceSupport extends Specification {
def static sharedSource = new SharedSource()
}
class SharedSource {
public SharedSource() {
println "Created shared source. Its our heavy resource!"
}
}
class SpockTest1 extends SharedResourceSupport {
def "sample test" () {
expect:
sharedSource != null
}
}
class SpockTest2 extends SharedResourceSupport {
def "another test" () {
expect:
sharedSource != null
}
}
Note that the shared resource is defined with "static", so that it will be created only once when the first test will access it.
As different strategies to deal with this: You might want to consider traits, if your test already inherits from another class, or expose shared resource as a Singleton so that it will guarantee that only one instance exists.
Try to run both tests and you'll see that that the line "Created shared source..." is called only once
The praise for the right answer belongs to Mark Bramnik when he wrote:
In general, Spock is a JUnit After all (that's why surefire plugin can run it without any additional hassle), so all approaches to the Suites should work
While this is the correct answer, the sample code in his answer refers to another scenario. So I am going to provide it here for reference. I do not expect this answer to get accepted, but if others read it they also should find sample code explaining how to use the feature in Spock:
Sample Spock tests:
package de.scrum_master.stackoverflow
class FooTest extends Specification {
def test() {
expect:
println "FooTest"
}
}
package de.scrum_master.stackoverflow
class BarTest extends Specification {
def test() {
expect:
println "BarTest"
}
}
Test suite:
package de.scrum_master.stackoverflow
import org.junit.AfterClass
import org.junit.BeforeClass
import org.junit.runner.RunWith
import org.junit.runners.Suite
import spock.lang.Specification
#RunWith(Suite.class)
#Suite.SuiteClasses([FooTest, BarTest])
class SampleTestSuite {
#BeforeClass
static void beforeTests() throws Exception {
println "Before suite"
}
#AfterClass
static void afterTests() throws Exception {
println "After suite"
}
}
Console log:
Before suite
FooTest
BarTest
After suite
Actually, it is possible in spock, assuming your code could be static.
To perform one-time initialization (spinup a container, start a test zookeeper cluster or whatever), just create a static singleton holder like the following:
class Postgres {
private static PostgresContainer container
static void init() {
if (container != null)
return
container = new PostgresContainer()
container.start()
}
static void destroy() {
if (container == null)
return
container.stop()
container = null
}
}
Then you need an abstract class for your integration tests, something like:
class IntegrationTest extends Specification {
def setup() {
init()
}
static void init () {
Postgres.init()
}
def cleanup() {
// do whatever you need
}
static void destroy() {
Postgres.destroy()
}
}
Now, cleanup is a little bit tricky - specially if you have some non-daemon threads preventing jvm from shutting down. This might cause your test suite to hang.
You can either use shutdownHoooks or use the spock AbstractGlobalExtension mechanism.
You can actually execute some code right after spock executes all the specs.
For our postgres scenario, we'd have something like:
class IntegrationTestCleanup extends AbstractGlobalExtension {
#Override
void stop() {
IntegrationTest.destroy()
}
}
There's one missing puzzle to make it work - you need to provide a special file under src/test/resources/META-INF.services/org.spockframework.runtime.extension.IGlobalExtension that references your extension. That file should contain a single line pointing to your extension, like
com.example.IntegrationTestCleanup
This will make spock recognize it. Keep in mind it will be executed in dedicated spock thread.
I do realize it kind of duplicates the accepted answer, but I was recently struggling with performing a global cleanup in spock so I thought it could be useful.

Deserializing data which can be object or boolean

I'm using maven and jersey with the following dependencies
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.25</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.25</version>
</dependency>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.9.1</version>
</dependency>
I'm using the
maven-jaxb2-plugin
plugin to generate classes from an xsd.
I'm trying to deserialize json which can be received in two ways:
{
"config": {
"field1": 1,
"field2": 2,
"object1": {
.
.
}
}
}
or
{
"config": false
}
For the latter I would expect
{
"config": {}
}
but this is not the case nor do I have influence on that.
When I deserialize this I get an exception
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.my.model.ConfigMap out of VALUE_FALSE token
It's clear why I get this exception.
I've been trying to use a custom deserializer to get around this but unsuccessful.
public class ConfigTypeDeserializer extends JsonDeserializer<ConfigType> {
#Override
public ConfigType deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
ObjectCodec cd = jsonParser.getCodec();
JsonNode node = cd.readTree(jsonParser);
ConfigType object = new ObjectFactory().createConfigType();
if (node.isBoolean()) {
return object;
}
// now I know its not a weird response so now I want to deserialize as usual
return object;
}
}
So I check if I see the weird response and if so I return an empty object and if not I want to return the object by deserializing it a usual because the object is too complex to completely build it manually in this deserializer. But I did not find a way to do this. I can e.g. call
cd.readValue(jsonParser,ConfigType.class);
but this does produce a ConfigType object but the contents are not correct. I'm not getting the expected object types.
So I want to know if it is possible to use (or continue) the existing deserialization code from my custom deserializer.
If that is not possible, is there another way to do this?
I found a really neat library
https://github.com/jonpeterson/jackson-module-json-interceptor
With maven:
<dependency>
<groupId>com.github.jonpeterson</groupId>
<artifactId>jackson-module-json-interceptor</artifactId>
<version>1.0.0</version>
</dependency>
which enabled me to intercept the deserialisation process just before it deserialises the object.
You can use this annotation
#JsonInterceptors(beforeDeserialization = {
MyDeserializationInterceptor.class
})
public class MyProblematicObject {
..
}
In my interceptor class I can do this
public class MyDeserializationInterceptor implements JsonInterceptor {
#Override
public JsonNode intercept(JsonNode node, JsonNodeFactory nodeFactory) {
JsonNode config = node.findValue("config");
// convert boolean to object
if (node.isObject() && config.isBoolean()) {
ObjectNode objectNode = nodeFactory.objectNode();
((ObjectNode)node).set("config",objectNode);
}
return node;
}
}
And the deserialisation process happily continues :)
Thank you Jon Peterson !!

How do I Mock SpringApplication.run

I have a File handler for Spring Batch that I want to test.
SpringApplication.run() is a static method for which I would like to verify the arguments passed to it.
Does this mean I need to go down the PowerMock path or is there something in the SpringFramework that will enable me to test this?
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;
}
My test class has the following annotations which don't seem to be working:
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
#SpringBootTest
#PrepareForTest(SpringApplication.class)
What am I missing?
The exception getting thrown is:
java.lang.IllegalStateException: Failed to transform class with name org.springframework.boot.SpringApplication. Reason: cannot find
org.springframework.web.context.support.StandardServletEnvironment
This occurs when the #PrepareForTest(SpringApplication.class) is processed. I'm testing a Spring Batch application so there is no web environment and I've also added.
#SpringBootTest(webEnvironment=WebEnvironment.NONE)
As I share your dislike for PowerMock, the first answer is unfortunately: the method that you have written right now - yes that can only be tested using PowerMock.
So, if you want to test that method; you have to use PowerMock. Or you take the minimal risk ... and simply don't test it.
Beyond that: I recommend to put that method into some interface; you simply want to prevent that this static call gives you trouble when you start testing other methods that want to call handleFile() - then you want to be able to mock that call; to prevent that static call inside to happen.
This issue due to the exception that I was having was due to a missing entry in the pom.xml, which frustrates me a bit with the SpringFramework since I'm working only in a batch application and have no web or servlet components whatsoever in this test. The missing pom entry was.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
The other spring dependecies that I had were
<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>
In order to test this, I did take the approach of PowerMock with externalizing some of the methods so that I could test them and even though I'm testing with a Spring Application, I was able to exclude the SpringRunner that loads the context to simplify this test. Below is my implementation class as well as the test class that tested it.
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;
}
}
And here's the test class
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.if you want to verify args in your tests, you need to return it to caller code of method handleFile(file) and currently you are doing - return null; , instead you should return args ( if method signature can be changed ).
I have assumed that handleFile method is in InitialFileBatchApplication class.
#Test
public void testHandleFile() {
File file = new File("ABC");
String[] response = new InitialFileBatchApplication().handleFile(file);
//Verify response here
}
Above will actually kick off your job.
2.If you wish to mock - SpringApplication.run as it is , PowerMock is the way to go. You should indicate in question as what error you are getting with current set up.
3.Mockito is inbuilt in Spring Test now so if you can refactor your code to have a non - static method call the static method then you can mock non - static method and that will eventually mock your static call. #MockBean annotation is part of Spring Test.
4.If Mocking SpringApplication.run in spring batch is equivalent to not running the job but simply initializing the context then purpose can be achieved by saying , spring.batch.job.enabled=false in application.properties. Only that your unit tests will have to wait for real call to - SpringApplication.run to complete but job will not kick off.
Code refactoring is always encouraged to make your code unit testable in addition to functionally being correct so don't hesitate to refactor to overcome framework limitations.
Hope it helps !!

Resources