Code Junkie
Code Junkie

Reputation: 7788

Get files from resource dir for unit test but absolute path for prod

I have a springboot commandline app where one of the production commandline args is the absolute base path. For this example we will call it

"/var/batch/"

I'm setting the basepath in my production.yml file like so with a default value.

company: basePath: ${basePath:/var/default/}

I then have an ApplicationConfig.java file that uses that base path to create a bunch of file paths like so.

@ConfigurationProperties(prefix = "company")
public class ApplicationConfig {

    private String basePath;

    public String getPrimaryCarePath() {
        return basePath + "ADAP-2-PCProv.dat";
    }

    public String getPrimaryCareDetailPath() {
        return basePath + "ADAP-2-" + getBatchNo() + ".det";
    }

    ... additional files. 

}

Lastly the file paths get passed into my css parser like so.

public List<T> readCsv() throws IOException {

    try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(filePath))) {
        return new CsvToBeanBuilder(bufferedReader)
                .withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_SEPARATORS)
                .withType(subClass)
                .withSeparator('\t')
                .withIgnoreLeadingWhiteSpace(true)
                .build().parse();
    }
}

Now everything works fine in production, but we face some issues when attempting to run mutation test. It appears as if the csv parser is looking for an absolute path rather than a relative path. We have the following path in our application-test.yml file.

company:
  basePath: src/test/resources/

All our test files are stored in the test resources package, so my question is how can we use a relative path to the test resources populating the ApplicationConfig.java file while still being able to use an absolute path for production? I was thinking I could override the basepath with the test setup using ClassPathResource, but was wondering if there was a better approach.

Upvotes: 1

Views: 432

Answers (1)

Adina Rolea
Adina Rolea

Reputation: 2109

You need 2 types of configurations : one for resources and one for absolute path.

I would suggest to add a new property app.file.path.type with values resources and absolute. You can define a new interface named FileProvider.

public interface FilePathProvider(){
    Path getFilePath();
}

You can define 2 different beans with @ConditionalOnProperty and set the file path strategy:

@Configuration
public class ApplicationConfig{

      @Bean
      @ConditionalOnProperty(
            name = "app.file.path.type", 
            havingValue = "absolute")
      public FilePathProvider absoluteFilePathProvider(ApplicationConfig applicationConfig){
           return () -> Paths.get(applicationConfig.getBasePath());
      }

     @ConditionalOnProperty(
            name = "app.file.path.type", 
            havingValue = "resources")
      @Bean
      public FilePathProvider resourceFilePathProvider(ApplicationConfig applicationConfig){
           return () -> Paths.get(this.getClass().getClassLoader().getResource(applicationConfig.getBasePath()).getPath());
      }
} 

In development and test mode, you will have app.file.path.type=resources and in production you will have app.file.path.type=absolute. The advantage of this approach is that you can set the property to absolute in development as well.

Upvotes: 1

Related Questions