I'm working on a coding challenge that tasks me with taking a file with a dictionary, reading from it, and then replacing the matching words from the input file with what is found in the dictionary.

I have a few concerns with my code.

1. I don't want to overengineer a task that seems simple, but I also don't want to trivialize the complexity of certain I/O operations or make trivial tests for it. As a result I've created one data class that processes the dictionary from the input file and two service classes that implement two interfaces. See image below.

[![enter image description here](https://i.stack.imgur.com/0ocEa.png)](https://i.stack.imgur.com/0ocEa.png)

2. That being said I have concerns about my business logic class, FileContentReplacementService, because the code seems messy and I feel like there are some things that could be improved but I just can't put my fingers on them at this very moment. Below is the full class:

**FileContentReplacementService**

```
import java.io.*;
import java.util.Map;

import Challenge2.model.FileBasedDictionary;
import org.apache.commons.io.LineIterator;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class FileContentReplacementService implements ContentReplacementService {

    private static final Logger LOGGER = LogManager.getLogger(FileContentReplacementService.class);
    private final RetrieverService retrieverService;
    private final FileBasedDictionary fileBasedDictionary;
    private final String outputFileName;

    public FileContentReplacementService(RetrieverService retrieverService,
                                         FileBasedDictionary fileBasedDictionary,
                                         String outputFileName) {
        this.retrieverService = retrieverService;
        this.fileBasedDictionary = fileBasedDictionary;
        this.outputFileName = outputFileName;
    }

    public boolean areMatchingWordsReplace(){
        String fileName = "src/main/resources/" + outputFileName;
        try {
            applyDictionaryToFile(fileBasedDictionary, retrieverService.getBufferedReader(), fileName);
        } catch (IOException ioe) {
            LOGGER.error(String.format("File not reachable \n %s", ExceptionUtils.getStackTrace(ioe)));
            return false;
        }

        return true;
    }

    private void applyDictionaryToFile(FileBasedDictionary fileBasedDictionary,
                                       BufferedReader bufferedReader,
                                       String fileName) throws IOException
    {
        FileOutputStream fileOutputStream = new FileOutputStream(fileName);
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
        LineIterator lineIterator = new LineIterator(bufferedReader);
        while (lineIterator.hasNext()) {
            String line = lineIterator.nextLine();
            bufferedOutputStream.write(replaceWords(line, fileBasedDictionary.getDictionary()));
        }
    }

    private byte[] replaceWords(String line, Map<String, String> dictionary) {
        if (line.isEmpty()) {
            return "\n\n".getBytes();
        }

        for (Map.Entry<String, String> entry : dictionary.entrySet()) {
            line = line.replaceAll(entry.getKey(), entry.getValue());
        }

        return line.getBytes();
    }
}

```

3. Is there any way to trigger the exception from the try/catch block of FileContentReplacementService? I've made a few tries but I could only trigger it by closing the BufferedReader and then flushing it, but I can only do that inside the method. My test, see below, is currently not covering that bit and I would like to know if there's something that can be done to cover it.

**FileContentReplacementServiceTest**

```
import Challenge2.model.FileBasedDictionary;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import java.io.*;
import java.util.Map;

import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class FileContentReplacementServiceTest {
    @Mock
    FileBasedDictionary fileBasedDictionary;
    @Mock
    FileRetrieverService fileRetrieverService;
    @Mock
    BufferedReader bufferedReader;

    FileContentReplacementService fileContentReplacementService;

    @Test
    public void givenValidFile_WhenWordsAreReplaced_ThenReplaceMatchingWordsIsCalled() throws IOException {
        when(fileRetrieverService.getBufferedReader()).thenReturn(bufferedReader);
        when(bufferedReader.readLine()).thenReturn("Test2", "", null);
        when(fileBasedDictionary.getDictionary()).thenReturn(Map.of("Test1", "Test2"));
        fileContentReplacementService = new FileContentReplacementService(fileRetrieverService, fileBasedDictionary, "\\testOutput\\test.txt");
        assertTrue(fileContentReplacementService.areMatchingWordsReplace());
    }
}

```

4. My FileRetrieverService is basically untesteable and, despite my best efforts, I just can't find a way to be able to test it and maintain decent code quality and/or not break a number of SOLID principles.

**FileRetrieverService**

```
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Objects;

public class FileRetrieverService implements RetrieverService {

    private final String fileName;

    public FileRetrieverService(String fileName) {
        this.fileName = fileName;
    }

    @Override
    public BufferedReader getBufferedReader(){
        return new BufferedReader(new InputStreamReader(Objects.requireNonNull(
                getClass().
                getClassLoader().
                getResourceAsStream(fileName))));
    }
}

```

**FileRetrieverServiceTest**

```
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import java.io.BufferedReader;

import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class FileRetrieverServiceTest{
    @Mock
    BufferedReader bufferedReader;
    @Mock
    FileRetrieverService fileRetrieverService;

    @Test
    public void givenFileName_WhenReturnBufferedReader_ThenReturnReader(){
        when(fileRetrieverService.getBufferedReader()).thenReturn(bufferedReader);
        assertNotNull(fileRetrieverService.getBufferedReader());
    }
    @Test(expected = NullPointerException.class)
    public void givenInvalidFileName_ThenFailFast(){
        doThrow(NullPointerException.class).when(fileRetrieverService).getBufferedReader();
        fileRetrieverService.getBufferedReader();
    }
}

```

I would really appreciate it if someone could take a look at the code above and give me a few pointers as to what improvements could be done to make the code more easily testable and better designed.