0

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 two arrays before overwriting and after overwriting, so I made it, but unfortunately, it says that actual array is null. I am using TemporaryFolder so that it can be easily deleted after test.

Method I want to unit test + method that is needed to test overwrite method.

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 ContentFileRetriever contentFileRetriever;

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

    ...

    String[] retrieveRankingData(String rankingPathFile) {
        return contentFileRetriever.getContent(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();
        }
    }
}

Test:

public class RankingSystemServiceTest {

    @Rule
    public TemporaryFolder tempFolder = new TemporaryFolder();

    @Mock
    ContentFileRetriever contentFileRetriever;

    private RankingSystemService rankingSystemService = new RankingSystemService(contentFileRetriever);

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        rankingSystemService = new RankingSystemService(contentFileRetriever);
    }


    @Test
    public void overwriteFileWithGivenResult() throws IOException {
        File rankingFile = tempFolder.newFile("rankingText.txt");
        String rankingFilePath = rankingFile.getPath();

        String[] actualResultBeforeOverwriting = rankingSystemService.retrieveRankingData(rankingFilePath);
        String[] expectedResultBeforeOverwriting = {};

        assertArrayEquals(expectedResultBeforeOverwriting, actualResultBeforeOverwriting);

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

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

        assertArrayEquals(expectedResultAfterOverwriting, afterOverwriting);
    }

getContent which retrieve content:

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

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

Stacktrace:

java.lang.AssertionError: actual array was null

    at org.junit.Assert.fail(Assert.java:88)
    at org.junit.internal.ComparisonCriteria.assertArraysAreSameLength(ComparisonCriteria.java:71)
    at org.junit.internal.ComparisonCriteria.arrayEquals(ComparisonCriteria.java:37)
    at org.junit.Assert.internalArrayEquals(Assert.java:532)
    at org.junit.Assert.assertArrayEquals(Assert.java:283)
    at org.junit.Assert.assertArrayEquals(Assert.java:298)
    at rankingsystem.RankingSystemServiceTest.overwriteFileWithGivenResult(RankingSystemServiceTest.java:61)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
pipilam
  • 587
  • 3
  • 9
  • 22
  • 1
    You mocked ContentFileRetriever. So it's now a mock instead of being an actual ContentFileRetriever. So its methods don't do anything anymore, and just return default values (i.e. null, in this case). If you want to test your service with an actual ContentFileRetriever, then don't mock it. – JB Nizet Apr 19 '19 at 07:39
  • Then, when I should mock instead of creating conrete instance? I though I need to Mock all dependencies of the Service – pipilam Apr 19 '19 at 07:49
  • See https://stackoverflow.com/a/28783849/571407 for an explanation on the principle of mocking. – JB Nizet Apr 19 '19 at 07:51
  • Yes, I have read it, but still dont get it. I need to pass a dependency of contentFileRetrieverService, so why cant I mock it? – pipilam Apr 19 '19 at 07:59
  • Because your specific test relies on the **actual** behavior of the service (i.e. actually read the bytes in the file) to work. So if you mock it, your test doesn't make any sense anymore. You can use a mock ContentFileRetriever if, in your test, you use something else than the ContentFileRetriever to read what is in the file before and after the call to the overwriteFileWithGivenResult(). – JB Nizet Apr 19 '19 at 08:08
  • So is it integration test? – pipilam Apr 19 '19 at 08:12
  • I wouldn't call that an integration test, no. But if you prefer calling it that way... – JB Nizet Apr 19 '19 at 08:14
  • I read that if I use a real instance then it is integration test, when I mock everything then it is unit test. – pipilam Apr 19 '19 at 08:16

1 Answers1

0

According to JB Nizet user I need to remove mock of ContentFileRetriever and create instance of ContentFileRetriever, and it works.

ContentFileRetrieverService contentFileRetrieverService = new ContentFileRetrieverService();
pipilam
  • 587
  • 3
  • 9
  • 22