How to mock FileInputStream and other *Streams

前端 未结 5 1963
暖寄归人
暖寄归人 2021-01-14 11:47

I have class that gets GenericFile as input argument reads data and does some additional processing. I need to test it:

public class RealCardParser {

    pu         


        
相关标签:
5条回答
  • 2021-01-14 11:57

    Maybe this is a bad idea, but my first approach would have been creating an actual test-file rather than mocking the stream object.

    One could argue that this would test the GenericFile class rather than the getBufferedReader method.

    Maybe an acceptable way would be to return an actually existing test-file through the mocked GenericFile for testing the getBufferedReader?

    0 讨论(0)
  • 2021-01-14 12:06

    You can mock FileInputStream by using PowerMockRunner and PowerMockito. See the below code for mocking-

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({
            FileInputStream.class
    })
    public class A{
    
     @Test
            public void testFileInputStream ()
                        throws Exception
           {
               final FileInputStream fileInputStreamMock = PowerMockito.mock(FileInputStream.class);
               PowerMockito.whenNew(FileInputStream.class).withArguments(Matchers.anyString())
                                   .thenReturn(fileInputStreamMock);
        //Call the actual method containing the new constructor of FileInputStream 
    
            }
    }
    
    0 讨论(0)
  • 2021-01-14 12:10

    When you are having this question. You are probably not following dependency inversion principle correctly. You should use InputStream whenever it's possible. If your write your FileInputStream adapter method like this:

    class FileReader {
        public InputStream readAsStream() {
            return new FileInputStream("path/to/File.txt");
        }
    }
    

    Then you can mock the method to return ByteArrayInputStream alternatively. This is much easier to deal with, because you only need to pass a string to the stream instead of dealing with the specific FileInputStream implementation.

    If you are using mockito to mock, the sample goes like this:

    FileReader fd = mock(FileReader());
    String fileContent = ...;
    ByteArrayInputStream bais = new ByteArrayInputStream(fileContent);
    when(fd.readAsStream()).thenReturn(bais);
    
    0 讨论(0)
  • 2021-01-14 12:11

    I would first extract the creation of the Stream into a dependency. So your RealCardParser gets a StreamSource as a dependency.

    Now you can take appart your problem:

    1. for your current test provide a mock (or in this case I would prefer a fake) implementation returning a Stream constructed from a String.

    2. Test the actual StreamSource with a real file, ensuring that it returns the correct content and what not.

    0 讨论(0)
  • 2021-01-14 12:23

    I know this isn't the answer that you want.

    The idea of unit testing is to make sure your logic is correct. Unit tests catch bugs where incorrect logic has been written. If a method contains no logic (that is, no branching, looping or exception handling), then it is uneconomical to unit test it. By that, I mean that a unit test costs money - time to write it, and time to maintain it. Most unit tests pay us back for that investment, either by finding bugs, or re-assuring us that there are no bugs in the domain of what is being tested.

    But a unit test for your getBufferedReader method would not pay you back for our investment. It has a finite cost, but zero benefit, because there is no actual logic that can go wrong. Therefore, you should NOT write such a unit test. If your Cobertura settings or your organisational standards require the existence of such a unit test, then those settings or standards are WRONG and should be changed. Otherwise, your employer's money is being spent on something that has an infinite cost:benefit ratio.

    I strongly recommend that your standards are changed so that you only write unit test for methods that contain branching, looping or exception handling.

    0 讨论(0)
提交回复
热议问题