Home > Software design >  Refactor java static method to make it testable
Refactor java static method to make it testable

Time:07-31

I want to make this code testable but the URI and File instance created inside the method are giving me problems. I am not able to define mock behavior for them and I don't want to use PowerMock because they don't reflect on Jacoco's test coverage.
If possible can we refactor the code somehow. It would be preferable if we could retain the static nature of the method. As changing that, would mess other parts of the code.

public static List<String> getAbsoluteFilePaths(String dirUrl) throws URISyntaxException {
        URI uri = new URI(dirUrl);
        File folder = new File(uri);
        File[] fileList = folder.listFiles();
        List<String> fileNames = new ArrayList<>();

        if (fileList != null) {
            for (File file : fileList) {
                String fileOrDirUrl = uri.getScheme()   "://"  
                        (uri.getAuthority() != null ? uri.getAuthority() : "") 
                        file.getAbsolutePath();

                if (file.isFile())
                    fileNames.add(fileOrDirUrl);
                else if (file.isDirectory())
                    fileNames.addAll(getAbsoluteFilePaths(fileOrDirUrl));
            }
        }
        return fileNames;
    }

CodePudding user response:

Beside the question if it's useful in this case to mock File and URI you could extract the creation of an object via a functional interface.

    private static final Function<String, File> fileFactory = File::new;
    
    public static List<String> getAbsoluteFilePaths(String dirUrl) throws URISyntaxException {
        File folder = fileFactory.apply(dirUrl);
        
        URI uri = folder.toURI();
        File[] fileList = folder.listFiles();
        List<String> fileNames = new ArrayList<>();

        if (fileList != null) {
            for (File file : fileList) {
                String fileOrDirUrl = uri.getScheme()   "://"
                          (uri.getAuthority() != null ? uri.getAuthority() : "")
                          file.getAbsolutePath();

                if (file.isFile()) {
                    fileNames.add(fileOrDirUrl);
                } else if (file.isDirectory()) {
                    fileNames.addAll(getAbsoluteFilePaths(fileOrDirUrl));
                }
            }
        }
        return fileNames;
    }

CodePudding user response:

According to the specification, the used constructor of class File sets some preconditions that must be met: e.g., the URI has to be absolute, its scheme has to be 'file' and its authority has to be undefined.

Therefore, the construction of the URI can be left to method File#toURI(), so that you can split the method into two testable parts:

class SomeClass {
    public static List<String> getAbsoluteFilePaths(String dirUrl) throws URISyntaxException {
        URI uri = new URI(dirUrl);
        File folder = new File(uri);
        return getFileUris(folder);
    }
    
    public static List<String> getFileUris(File folder) {
        File[] fileList = folder.listFiles();
        List<String> fileNames = new ArrayList<>();

        if (fileList != null) {
            for (File file : fileList) {
                if (file.isFile())
                    fileNames.add(file.toURI().toString());
                else if (file.isDirectory())
                    fileNames.addAll(getFileUris(file));
            }
        }
        return fileNames;
    }
}    
  • Related