Search code examples
javaunit-testingjunitjunit4

JUnit - How to unit test method that reads files in a directory and uses external libraries


I have this method that I am using in a NetBeans plugin:

public static SourceCodeFile getCurrentlyOpenedFile() {
        MainProjectManager mainProjectManager = new MainProjectManager();
        Project openedProject = mainProjectManager.getMainProject();

        /* Get Java file currently displaying in the IDE if there is an opened project */
        if (openedProject != null) {
            TopComponent activeTC = TopComponent.getRegistry().getActivated();
            DataObject dataLookup = activeTC.getLookup().lookup(DataObject.class);
            File file = FileUtil.toFile(dataLookup.getPrimaryFile());                   // Currently opened file

            // Check if the opened file is a Java file
            if (FilenameUtils.getExtension(file.getAbsoluteFile().getAbsolutePath()).equalsIgnoreCase("java")) {
                return new SourceCodeFile(file);
            } else {
                return null;
            }

        } else {
            return null;
        }
    }

Basically, using NetBeans API, it detects the file currently opened by the user in the IDE. Then, it loads it and creates a SourceCodeFile object out of it.

Now I want to unit test this method using JUnit. The problem is that I don't know how to test it.

Since it doesn't receive any argument as parameter, I can't test how it behaves given wrong arguments. I also thought about trying to manipulate openedProject in order to test the method behaviour given some different values to that object, but as far as I'm concernet, I can't manipulate a variable in JUnit that way. I also cannot check what the method returns, because the unit test will always return null, since it doesn't detect any opened file in NetBeans.

So, my question is: how can I approach the unit testing of this method?


Solution

  • Well, your method does take parameters, "between the lines":

    MainProjectManager mainProjectManager = new MainProjectManager();
    Project openedProject = mainProjectManager.getMainProject();
    

    basically fetches the object to work on.

    So the first step would be to change that method signature, to:

    public static SourceCodeFile getCurrentlyOpenedFile(Project project) {
    ...
    

    Of course, that object isn't used, except for that null check. So the next level would be to have a distinct method like

    SourceCodeFile lookup(DataObject dataLookup) {
    

    In other words: your real problem is that you wrote hard-to-test code. The "default" answer is: you have to change your production code, to make easier to test.

    For example by ripping it apart, and putting all the different aspects into smaller helper methods.

    You see, that last method lookup(), that one takes a parameter, and now it becomes (somehow) possible to think up test cases for this. Probably you will have to use a mocking framework such as Mockito to pass mocked instances of that DataObject class within your test code.

    Long story short: there are no detours here. You can't test your code (in reasonable ways) as it is currently structured. Re-structure your production code, then all your ideas about "when I pass X, then Y should happen" can work out.

    Disclaimer: yes, theoretically, you could test the above code, by heavily relying on frameworks like PowerMock(ito) or JMockit. These frameworks allow you to contol (mock) calls to static methods, or to new(). So they would give you full control over everything in your method. But that would basically force your tests to know everything that is going on in the method under test. Which is a really bad thing.