-1

Im trying to unit test my overwriting method that overwrites the file (or create new one if given file does not exists). My idea was to compare to arrays before overwriting and after overwriting, so I made it, but unfortunately (as always) NPE occured.

Here is the method with the class I want to test:

package rankingsystem;

import contentfile.ContentFileRetriever;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

public class RankingSystemService {

    private static final int FIRST_PART = 0;
    private static final int SECOND_PART = 1;
    private ContentFileRetriever contentFileRetriever;

    public RankingSystemService(ContentFileRetriever contentFileRetriever) {
        this.contentFileRetriever = contentFileRetriever;
    }

...

    String[] retrieveRankingData(String rankingPathFile) {
        return contentFileRetriever.getContentFile(rankingPathFile);
    }

    void overwriteFileWithGivenResult(String name, long timeOfFinishingGame, String rankingPathFile) {

        try (FileWriter writer = new FileWriter(rankingPathFile, true);
             BufferedWriter bufferedWriter = new BufferedWriter(writer)) {
            bufferedWriter.write(name + " " + timeOfFinishingGame);
            bufferedWriter.newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Here is the ContentFileRetriever class:

package contentfile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class ContentFileRetrieverService implements ContentFileRetriever {

    @Override
    public String[] getContentFile(String pathName) {

        Stream<String> contentFileStream;
        try {
            contentFileStream = Files.lines(Paths.get(pathName));
        } catch (IOException e) {
            throw new IllegalArgumentException(e);
        }

        return contentFileStream.toArray(String[]::new);
    }
}

Here is the test:

package rankingsystem;

import contentfile.ContentFileRetriever;
import contentfile.ContentFileRetrieverService;
import org.junit.Test;
import org.mockito.Mock;

import java.util.LinkedHashMap;
import java.util.Map;

import static org.junit.Assert.*;

public class RankingSystemServiceTest {

    @Mock
    ContentFileRetrieverService contentFileRetrieverService;

    private RankingSystemService rankingSystemService = new RankingSystemService(contentFileRetrieverService);

   ...

    @Test
    public void overwriteFileWithGivenResult() {
        String pathFile = "src\\test\\java\\resources\\RankingFile.txt";

        String[] beforeOverwriting = rankingSystemService.retrieveRankingData(pathFile);
        String[] expectedResultBeforeOverwriting = {};

        assertArrayEquals(expectedResultBeforeOverwriting, beforeOverwriting);

        rankingSystemService.overwriteFileWithGivenResult("Piotr", 1L, pathFile);

        String[] afterOverwriting = rankingSystemService.retrieveRankingData(pathFile);
        String[] expectedResultAfterOverwriting = {"Piotr 1"};

        assertArrayEquals(expectedResultAfterOverwriting, afterOverwriting);
    }
}

Here is the stacktrace:

java.lang.NullPointerException
    at rankingsystem.RankingSystemService.retrieveRankingData(RankingSystemService.java:38)
    at rankingsystem.RankingSystemServiceTest.overwriteFileWithGivenResult(RankingSystemServiceTest.java:39)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

What am I making wrong?

pipilam
  • 587
  • 3
  • 9
  • 22
  • 1
    You aren't defining any behavior on the mock. Default behavior is to return `null`. Next to that you are missing an `@RunWith(MockitoJUnitRunner.class)` to have Mockito parse the `@Mock` annotation. – M. Deinum Apr 18 '19 at 10:45
  • 1
    The location of the NPE means there is only one explanation. The `contentFileRetriever` field has been initialized (or updated) to `null`. – Stephen C Apr 18 '19 at 10:46
  • 1
    Possible duplicate of [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – DaveyDaveDave Apr 18 '19 at 10:46
  • @DaveyDaveDave I'd say that duplicate wouldn't help much in this case. There's no answer in there that would help here. – Federico klez Culloca Apr 18 '19 at 10:48
  • Okay. I solved it. Added @Before annotation + `MockitoAnnotations.initMocks(this); rankingSystemService = new RankingSystemService(contentFileRetrieverService);` Thanks guys. – pipilam Apr 18 '19 at 10:50
  • I would recommend to keep file operations out of your unittests, this way the unittests are independend of a real environment with existing paths and they keep running fast. Just build an interface for all file operations, call this interface from your code and inside the unittest you can check whether the expected file operations where triggered. – martinstoeckli Apr 18 '19 at 10:55
  • @martinstoeckli I should depened testing classes on abstracion, not on concrete classes? – pipilam Apr 18 '19 at 11:46
  • @pipilam - The best we can achieve is to test exactly the code/logic of the method we have written (the unit) and nothing more. In the situation above we also test whether the `FileWriter` works correctly in the given environment (could be a continous integration environment, another OS, or the system of a fellow developer) and we alter the system. Of course we can test the implementation of our concrete `FileWriter` class too, but this is worth a separate test for the FileWriter, and often those are just wrappers around development-language classes so we can consider them as already tested. – martinstoeckli Apr 18 '19 at 12:36
  • But the point is I want to test if the `FIleWriter` works correctly, I want to test if it overwrites correctly. Sorry, Im not enough advanced to make it right as you want, because I dont understand what you are saying. – pipilam Apr 18 '19 at 12:39
  • 1
    @pipilam - That's ok, it is just a recommendation, you are not doing something wrong - it is a good thing that you write tests. – martinstoeckli Apr 18 '19 at 12:41
  • @FedericoklezCulloca, while I agree that it might not give the specific answer "you need to initialise the mocks" the accepted answer to that question gives excellent advice about how to debug NPEs. The fact that this OP says in the question "(as always) NPE occured", together with the large quantity of code posted, rather than an MCVE implied to me that he/she doesn't know the simple steps required to track down the cause. The dupe I linked to would - at the very least - have allowed him/her to narrow the cause of the issue down to the mocking framework, to ask a more specific question. – DaveyDaveDave Apr 18 '19 at 12:52

1 Answers1

2

I solved it with help of guys in comments. Needed to add:

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
    rankingSystemService = new RankingSystemService(contentFileRetrieverService);
}
Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
pipilam
  • 587
  • 3
  • 9
  • 22