thisdotnull
thisdotnull

Reputation: 862

SpringJUnit4ClassRunner not working after packaging in Jar but works in IDE

I am packaging JUnit test cases and suites in a jar and trying to execute these using JUnit core from inside main. The issue is that when I execute these testcases after packaging in JAR, beans are not injected (which implies an issue with spring context.) However, when I execute main method from IDE, beans are injected and everything works.

These test cases have a parent class which is loading the spring context.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { AppConfig.class } )
public abstract class BaseTest {

    @Autowired
    protected WebDriver driver;

    @PreDestroy
    public void teardown() {
        ...
    }
}

A test class and suite-

public class SomeTestClass extends BaseTest {
    @Test
    public void someTestCase() {
        ...
    }
}


@RunWith(Suite.class)
@Suite.SuiteClasses({
    SomeTestClass.class
})
public class SomeTestSuite { }

There's a main method which is being used to execute these testcases/suites with JUnitCore.

    public static void main(String...args) {
        Result result = JUnitCore.runClasses(SomeTestSuite.class);

        if (result.wasSuccessful()) {
            LOGGER.info("All tests executed successfully: {}", result);
        } else {
            LOGGER.error("There are failures");
            for (Failure failure: result.getFailures()) {
                LOGGER.error("failure: {} msg: {} desc: {}", failure, failure.getMessage(), failure.getDescription(), failure.getException());
            }
        }
    }

I am getting NullPointerException when executing this via JAR but no issues when execute main method from within IDE.
I am using IntelliJ 2017.2.x, JUnit 4.12 for testcases and maven shade plugin 3.0 to package jar.

EDIT 1
Executing jar as -

java -jar myjar.jar

NPE when executing via JAR-

2017-11-29 10:16:00,567 [TestCasesExecutor:44] ERROR junit.framework.Test  - failure: testMethodName(testClass): null msg: null desc: testMethodName(testClass)
java.lang.NullPointerException
        at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:770)
        at org.openqa.selenium.support.ui.FluentWait.<init>(FluentWait.java:96)
        at org.openqa.selenium.support.ui.WebDriverWait.<init>(WebDriverWait.java:71)
        at org.openqa.selenium.support.ui.WebDriverWait.<init>(WebDriverWait.java:45)
        at com.mycom.SomeTestClass.setup(BaseTest.java:37)
        at com.mycom.testcases.SplunkGcpScoreCardTest.logoutFromGcpScorecard(SplunkGcpScoreCardTest.java:27)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
        at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
        at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
        at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
        at org.junit.runners.Suite.runChild(Suite.java:128)
        at org.junit.runners.Suite.runChild(Suite.java:27)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runners.Suite.runChild(Suite.java:128)
        at org.junit.runners.Suite.runChild(Suite.java:27)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:105)
        at org.junit.runner.JUnitCore.runClasses(JUnitCore.java:62)
        at org.junit.runner.JUnitCore.runClasses(JUnitCore.java:49)
        at com.mycom.TestCasesExecutor.main(TestCasesExecutor.java:37)

Background - I have some selenium test cases for an app in production. It creates an instance of headless chrome for execution. The reason these were wrapped as test cases is because ideally we wanted to integrate this with saucelabs (saucelabs needs selenium code wrapped as testcases for execution.) However, currently there are some constraints as to how saucelabs is setup in my organization and we can't go down that road as of today but while we figure this out, we kept writing this code. So now, I am trying to create a JAR with this code and deploy it in production. This way, I don't have to make a lot of changes when we are able to move with Saucelabs.

Upvotes: 1

Views: 952

Answers (1)

thisdotnull
thisdotnull

Reputation: 862

After troubleshooting through spring code and logs, I figured that it's failing because my JAR doesn't have spring.factories file in it's META-INF. Possible solutions-

  1. Change project to spring boot, enable auto-configuration and create a JAR using spring boot maven plugin which takes care of packaging it right.
  2. Create spring.factories file in src/main/resources/META-INF. You can write your own (refer spring doc) or copy spring.factories from any spring dependency in your project. Related question on SO.

I went with option 2 because it seemed easy in this scenario. I didn't need anything more than just spring.factories from spring-boot dependency, so option 1 would have been an overkill.

Upvotes: 1

Related Questions