-2

I have a Spring-boot app. I want to use variable from application.properties in class method but I have nullPointerException.

Here's a simple example that doesn't work.

application.properties:

#data paths
file.path=C:\\Users\\apodar\\autoTest

Config.java

package com.eserv.autotest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Config {

@Value("${file.path}")
String filePath;

    public String getFilePath() { return filePath; }
    public String getScreenshotsPath() {
        return getFilePath() + "/screenshots";
       }

}

AutotestApplication.java

package com.eserv.autotest;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.Transactional;


@SpringBootApplication(
        scanBasePackageClasses = {
            AutotestApplication.class,
       }
)
public class AutotestApplication implements CommandLineRunner {


    @Autowired DataSource dataSource;

    public static void main(String[] args) {
        SpringApplication.run(AutotestApplication.class, args);
    }

    @Transactional(readOnly = true)
    @Override
    public void run(String... args) throws Exception {

         System.out.println("DATASOURCE = " + dataSource);

    }
 }

SeleniumTestExecutionListener:

    public class SeleniumTestExecutionListener extends AbstractTestExecutionListener {

    @Inject Config config;

    private WebDriver webDriver;

    @Override
    public void afterTestMethod(TestContext testContext) throws Exception {
        if (testContext.getTestException() == null) {
            return;
        }
        File screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
        String testName = toLowerUnderscore(testContext.getTestClass().getSimpleName());
        String methodName = toLowerUnderscore(testContext.getTestMethod().getName());

        FileUtils.copyFile(screenshot, new File( config.getScreenshotsPath() + testName + "_" + methodName + "_" + screenshot.getName()));
    }

}

Why does config.getScreenshotsPath() method doesn't return path. config is null.

Andrei
  • 329
  • 1
  • 3
  • 8
  • can you provide your class annotated with @SpringBootApplication? – Miron Balcerzak Sep 06 '17 at 13:14
  • Autowiring doesn't work in a `TestExecutionListener`. – M. Deinum Sep 06 '17 at 13:16
  • Possible duplicate of [Spring @Value annotation always evaluating as null?](https://stackoverflow.com/questions/4130486/spring-value-annotation-always-evaluating-as-null) – Juan Carlos Mendoza Sep 06 '17 at 13:22
  • @MironBalcerzak I have edit post with SpringBootApplication class. – Andrei Sep 06 '17 at 13:28
  • SeleniumTestExecutionListener is not @Component? Then Spring doesn't care about its autowiring. Then autowired fields like config are not properly initialized. – Alexander Anikin Sep 06 '17 at 13:30
  • @M.Deinum: Could you please tell me how can a get the value from `application.properties` in `SeleniumTestExecutionListener`? – Andrei Sep 06 '17 at 13:31
  • Regardless the `TestExecutionListener` instances aren't under spring control (not the application context) but the test execution framework. You cannot auto wire into a `TestExecutionListener` for exactly that reason. You. need to retrieve the `ApplicationContext` from the `TestContext` and retrieve the `Config` object from that. – M. Deinum Sep 06 '17 at 13:34
  • @AlexanderAnikin: Even I annotate with @Component `SeleniumTestExecutionListener `, `config` is still null. – Andrei Sep 06 '17 at 13:35
  • @M.Deinum: your answer seems to be rightful but, because I'm beginner I don't understand so well. If is ok (some people say that I did not make any research effort ), could you please help me with references how to do that? Thank you. – Andrei Sep 06 '17 at 13:56
  • I basically explained that word for word... `testContext.getApplicationContex().getBean(Config.class)` if you want the code. – M. Deinum Sep 06 '17 at 13:57
  • @M.Deinum: It works in this way, thank you so much :) – Andrei Sep 06 '17 at 14:17

1 Answers1

0

Autowiring in a TestExecutionListener will not work. The creation and lifecycle of the TestExecutionListener instances is managed by the Test Context framework of Spring and that isn't part of the ApplicationContext but external. Hence auto wiring will not work.

If you want to use beans in your TestExecutionListener instead retrieve the ApplicationContext from the TestContext.

@Override
public void afterTestMethod(TestContext testContext) throws Exception {
    if (testContext.getTestException() == null) {
        return;
    }

    final Config config = testContext.getApplicationContext().getBean(Config.class);
    File screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
    String testName = toLowerUnderscore(testContext.getTestClass().getSimpleName());
    String methodName = toLowerUnderscore(testContext.getTestMethod().getName());

    FileUtils.copyFile(screenshot, new File( config.getScreenshotsPath() + testName + "_" + methodName + "_" + screenshot.getName()));
}
M. Deinum
  • 115,695
  • 22
  • 220
  • 224