12

I am testing a output stream in java something like below.

    Writer outputStream = getOutputStream(fileName);
    if(outputStream != null) {
        try {
            outputStream.write(inputText);
        }
        finally {
            outputStream.close();
        }
    }
    else {
        throw new IOException("Output stream is null");
    }

I am write a mockito test as below

public void testFileWrite() throws IOException {
    when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(outputStreamMock);
    doNothing().when(outputStreamMock).write(Matchers.anyString());
    doNothing().when(bufferedReaderMock).close();

    testObj.write(outputFileNameValidValue, reveredFileInput);

    verify(outputStreamMock).write(Matchers.anyString());
    verify(outputStreamMock).close();
}

The problem is when you create OutputStreamWriter(new FileOutputStream(filename)) a physical file on the disk is created.

Can we test Outputstream.write without actually writing a file on the disk?

Thanks Anand

A.H.
  • 63,967
  • 15
  • 92
  • 126
Anand
  • 121
  • 1
  • 2
  • 7
  • 1
    Please clarify - where do you create an `OutputStreamWriter` - I don't see it in your code. I would guess that it's within `getOutputStream` - except that you've stubbed this method out. You need to post all of your code if you want people to do a good job of helping you. Also, `getOutputStream` should probably be called something else (maybe `makeWriter`), because it doesn't get an `OutputStream`. – Dawood ibn Kareem Feb 18 '12 at 00:53
  • In getOutputStream method. The reason I moved it to the method with hope that mockito will not run the mthod and return the mock. but I am wrong. – Anand Feb 18 '12 at 06:22
  • After googling and reading few docs found out that PowerMock can do this easily. With expectNew or using suppressConstructor and Whitebox.setInsternalState. It is far easy to test such things with PowerMock. Thanks all for your comments and answers.. regards, Anand Barhate – Anand Feb 18 '12 at 06:24

5 Answers5

15

You can use ByteArrayOutputStream which writes the data in memory. You can read this with a ByteArrayInputStream.

An alternative is to write an expecting OutputStream which fails as soon as you attempt to write an incorrect byte. This can be helpful to see exactly where/why a test fails.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Ok.. so use ByteArrayOutputStream to write and then eventually I will have to use writeTo to write to the file? But sooner or later I will face the same problem, isnt it? XXStreamWriter will have to write the file and that is the bit I want to avoid using Mockito. – Anand Feb 17 '12 at 12:42
  • 1
    I don't understand. Why would you need to write to a file? – Peter Lawrey Feb 17 '12 at 12:45
2

You could try using System.out for your output which is actually a Printstream, which is a subclass of OutputStream

see: http://docs.oracle.com/javase/6/docs/api/java/lang/System.html http://docs.oracle.com/javase/6/docs/api/java/io/PrintStream.html

nwaltham
  • 2,067
  • 1
  • 22
  • 40
1

As other suggested already you need to be able to inject a mocked OutputStream in your class under test. As your class under test needs a OutputStream which writes into a given file, you will need to inject a mockable OutputStreamFactory into your class under test.

I have this code for you which is fully self contained:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.io.IOException;
import java.io.OutputStream;

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class Test9328173 {

    private ClassUnderTest testObj;

    @Mock
    private OutputStreamFactory factory;

    @Mock
    private OutputStream stream;

    @Before
    public void setUp() throws Exception {
        testObj = new ClassUnderTest();
        testObj.factory = factory;
    }

    @Test
    public void testFileWrite() throws Exception {
        when(factory.create("filename")).thenReturn(stream);

        testObj.write("filename", new byte[]{1, 2, 3});

        verify(stream).write(new byte[]{1, 2, 3});
        verify(stream).close();
    }

    private class ClassUnderTest {

        private OutputStreamFactory factory;

        public void write(String filename, byte[] content) throws IOException {
            OutputStream stream = factory.create(filename);
            try {
                stream.write(content);
            } finally {
                stream.close();
            }
        }
    }

    private interface OutputStreamFactory {

        OutputStream create(String filename);
    }
}
Alexander Kiel
  • 605
  • 6
  • 9
  • Indeed. A setter / constructor argument / @Inject annotation may be a bit easier than a factory, but this is the way to verify that the stream receives the right instructions. – avandeursen Mar 07 '12 at 09:55
0

You should mock up your getOutputStream: is should return mocked output stream object. Invocation of new FileOutputStream indeed creates file on disk.

Theoretically you can mock up file system itself but it is much more complicated.

And BTW if(outputStream != null) is redundant: stream can never be null. If it cannot be created the method should throw exception. It is not C, it is Java. :)

AlexR
  • 114,158
  • 16
  • 130
  • 208
  • Actually this is what I did when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(outputStreamMock); but when I call testObj.write(outputFileNameValidValue, reveredFileInput); it would still write the blank string to the file. So it seems I will have to mock the file system to avoid actually creating a file on the disk. – Anand Feb 17 '12 at 12:46
  • if(outputStream != null) agree on this. I'm just used to defensive programming :) – Anand Feb 17 '12 at 12:48
0

You should have the mocked getOutputStream(String) return a java.io.StringWriter and you can then assert that the expected content was written.

public void testFileWrite() throws IOException {
    StringWriter writer = new StringWriter();
    when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(writer);

    testObj.write(outputFileNameValidValue, reveredFileInput);

    assertEquals(reveredFileInput, writer.toString());

    verify(writer).close();
}
Justin Muller
  • 1,283
  • 13
  • 21