15

Within a Spring Component I have a @PostConstruct statement. Similar to below:

@Singleton
@Component("filelist")
public class FileListService extends BaseService {

    private List listOfFiles = new Arrays.list();

    //some other functions


    @PostConstruct
    public void populate () {

        for (File f : FileUtils.listFiles(new File(SystemUtils.JAVA_IO_TMPDIR), new String[]{"txt"},true)){
            listOfFiles.add(f.getName());
        }   
    }

    @Override
    public long count() throws DataSourceException {
        return listOfFiles.size();
    }

    //  more methods .....
}

During Unit tests I would not like to have the @PostConstruct function called, is there a way to telling Spring not to do post processing? Or is there a better Annotation for calling a initiation method on a class durning non-testing ?

CAMOBAP
  • 5,523
  • 8
  • 58
  • 93
Ben
  • 1,086
  • 3
  • 15
  • 30
  • Is it FileListService you want to test or other classes depending on it? – mrembisz Nov 05 '12 at 11:37
  • The FileListService is required by a Web Service which is being tested - public class FileWSTest extends JerseyTest, which is using grizzly web container – Ben Nov 05 '12 at 11:46
  • 3
    You can either mock it using a subclass or factor out the initialization part. You can place mock in package scanned only for tests and mark it as `@Primary`. – mrembisz Nov 05 '12 at 11:51
  • this (from mrembisz) worked - added the mock classes into the config directly with @Primary tag, and ensure that the injected/autowired were interface. one class override removing function and the other complete class mocked including the loading of database stuff, removed the need for a in-memory datbase during test ... how to give credit ? – Ben Nov 05 '12 at 12:25
  • I have reposted it as an answer. – mrembisz Nov 05 '12 at 13:08

4 Answers4

8

Any of:

  1. Subclass FileListService in your test and override the method to do nothing (as mrembisz says, you would need to place the subclass in package scanned only for tests and mark it as @Primary)
  2. Change FileListService so the list of files is injected by Spring (this is a cleaner design anyway), and in your tests, inject an empty list
  3. Just create it with new FileListService() and inject the dependencies yourself
  4. Boot up Spring using a different configuration file/class, without using annotation configuration.
artbristol
  • 32,010
  • 5
  • 70
  • 103
  • The FileListService is a @Component which is found by Spring using , so overriding wouldn't stop spring from finding it. Also the some PostConstruct will actually do other things, so i would need to inject a function and not data. I'll guess i would need a way of injecting a Mocked class that overrides the exsisting bean-id – Ben Nov 05 '12 at 11:49
7

Since you are not testing FileListService but a depending class, you can mock it for tests. Make a mock version in a separate test package which is scanned only by test context. Mark it with @Primary annotation so it takes precedence over production version.

mrembisz
  • 12,722
  • 7
  • 36
  • 32
4

Declare a bean to override the existing class and make it Primary.

@Bean
@Primary
public FileListService fileListService() {
 return mock(FileListService.class);
}
0

check the profile as this:

  @PostConstruct
    public void populate () {
       if (!Arrays.asList(this.environment.getActiveProfiles()).contains("test")) {    
         for (File f : FileUtils.listFiles(new File(SystemUtils.JAVA_IO_TMPDIR), new 
              String[]{"txt"},true)){
            listOfFiles.add(f.getName());
          } 

        }           
    }
schrom
  • 1,372
  • 1
  • 22
  • 36