3

I have code that creates directories and transfer files to it. I want to unit test it. But the problem is when i run the unit test these directories are created but i don't want that. I want the code to create these directories only when its running a production environment. I have googled about this, but all search results suggest the JUnit class TemporaryFolder. But that is not what i want. I am not creating directories inside my test cases. I am just testing code that creates them. So am not sure how TemporaryFolder class can help me with that. say i have code like below

public class Util {

    public File getLocation(String location) {
        File result = new File(location);

        if (!result.exists()) {
            result.mkdirs(); 
        }
        return result;
    }
}

How do I unit test such code? Every time I call

util.getLocation("base/location"); 

the directories base/location are being created but I don't want that. They should only be created when I run the code in production environment.

UPDATE Due to the comments on the question. I've decided to update my question. First the getLocation signature is a little misleading. That is not the exact code that i am testing, its kind of long and so i tried to convey the idea with that. It functions basically the same but the problem is that getLocation() takes no parameter as shown above. Inside getLocation another method is called which returns a string to a path. Which means i have no control over what is been used in creating the directories. And also i run both production and development environment and once these directories have been created while running production code, they should not be deleted even if the code is rebuilt because the unit test will be run on every build.

public File getLocationForReports() {

    String softwareHome = GeneralUtil.getSoftwareHome();
    File path = new Path(softwareHome, "reports").toFile();

    if (!path.exists()) {
        path.mkdirs();    
    }
    return path;
}

As you can see above i don't have control of what GeneralUtil.getSoftwareHome() returns so i cannot even send in a dummy location like "tmp/location" and delete later and i also don't want to delete these directories if they were created when the production code is run because I'll some files.

Stylishcoder
  • 1,142
  • 1
  • 11
  • 21
  • 3
    The only approach that makes sense to do this without JUnits Temporary Folder is IMHO by using a Mock-Framework like Mockito. Maybe this helps you: http://stackoverflow.com/questions/18977057/mock-file-filereader-and-bufferedreader-class-using-mockito. But what is your problem that the Unit-Tests creates folders/files?? You can define that everything should be deleted after your test was executed. Also, you can use other/relative pathes for the test so it can be executed in other environments – Supahupe Jul 01 '16 at 08:50
  • Remove them at the end of the test? – Manu Jul 01 '16 at 08:53
  • Create the folder, check if if has worked, delete it... – Supahupe Jul 01 '16 at 08:57
  • Of course, sometimes it makes sense that unit test ... test code and "nothing" happens. But heck: you are talking about creating directories, which can be easily deleted afterwards. Maybe that won't be a "pure" unit test; but hey: it would perfectly prove that your code is doing exactly what you want it to do. And you can still run it was part of any jenkins/eclipse unit test run. I think "I don't want directories be created" is simply "over thinking" here. – GhostCat Jul 01 '16 at 09:17
  • Ok i understand i can create the directories and delete them. But that is not what i want also. I run both production and development environment. The unit test is run only when am building the code. And when in production, that method is called to transfer some files. If i delete them inside unit test, won't they affect my production environment. I mean once those directories have been created in production environment. They should not be deleted no matter how many times i rebuild the code. – Stylishcoder Jul 01 '16 at 09:19
  • Please take a look at http://junit.org/junit4/javadoc/4.12/org/junit/rules/TemporaryFolder.html – Jakub Kubrynski Jul 01 '16 at 09:40
  • How do you distinguish production and dev environment then? Some system property, some flag somewhere? You can use that on deciding if directory should be deleted at the end of the test – Nadir Jul 01 '16 at 11:44
  • Instead of using `File` class, use Java NIO2 API and `Path` in concrete. You can then f.e. use an in-memory file system like Google's [`JimFS`](https://github.com/google/jimfs) in combination with NIOs [`Files`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html) class to create the folders and files only in-memory. – Roman Vottner Jul 01 '16 at 12:56

2 Answers2

6

I suggest to do whatever you can to not use PowerMock to do any testing.

PowerMock manipulates your production classes; it often leads to really bizarre errors (that you can hunt down for hours, without ever finding a real problem in your code); and it kills your ability to do coverage.

In other words: for me, the "need" for PowerMock very much translates to: your design isn't structured to allow for reasonable testing. And instead of investing into the big ugly PowerMock hammer ... you better spent time reworking your design!

In your case: get rid of calls to static methods; make sure that you can use dependency injection in order to provide mocked objects to your code. Meaning: frameworks like EasyMock allow you to create mocked objects that do whatever you want them to do. You pass such "prepared" mocks to your code under test; and then you have completely control over what will be going during your tests.

You see, in essence your problem is that your production code is doing too many things in one place; therefore you have such a hard time testing it. Rip it apart, put each "responsibility" found in that code into separate classes/methods; and test those individually.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
0

I suggest using PowerMock to create your tests. There are 2 ways to do this. Both will need PowerMock and the tests will be needed to be annotated like this: @RunWith(PowerMockRunner.class) @PrepareForTest(Class that you want to test.class)

First you can try to Mock out the static call to GeneralUtil.getSoftwareHome() using powermockito. PowerMockito mock single static method and return object

The second option is to mock out the constructor for the Path object and the calls it returns: mockito mock a constructor with parameter

This way you can test the functionality of your code.

Community
  • 1
  • 1
Flying Dutch Boy
  • 344
  • 3
  • 17